Easily install local NPM packages by simply referring to their local path

Directly installing a package with npm install and referring to its local path is a quick way to work with a local package. To be safe though, the usage of npm link is still recommended.

To work with local NPM packages on can reside to using npm link. You make a package available locally with npm link and later on symlink it into your project using npm link package:

cd ~/projects/node-redis    # go into the package directory
npm link                    # creates global link

cd ~/projects/node-bloggy   # go into some project directory
npm link redis              # link-install the redis package (by its name)

This methods works fine and – above all – allows you to have a package.json that has no record of that link. That way you can check it into Git and push it, while still using the local version.

A downside however is that this way of working change is not explicit: by checking your package.json you can’t really tell whether you’re using a locally linked version or not.


A more easy quick and dirty way of achieving this is to directly install a package by simply referring to its directory:

cd ~/projects/node-bloggy   # go into some project directory
npm install ../node-redis   # install the redis package by referring to its directory

Apart from symlinking the package into your project, your package.json will have been adjusted like this:

  "dependencies": {
    "redis": "file:../node-redis"

This change is explicit: a look at your package.json clearly tells you that you’re using a locally installed package.

⚠️ Do note that this way of working comes with a big caveat though: you may not commit this change into Git. While this change Works Fine on my Machine™ it won’t in your build system, your colleague their machine, …


So which technique to use when? Personally I go for:

  • npm link when adjusting an existing library (most likely a clone/fork to land a bugfix) while testing it in an existing project
  • npm install ../path when splitting off a new library from an existing project


Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

GitHub acquires npm

It was suggested that Microsoft/GitHub should have bought npm back in the day, instead of launching their own registry. Today is the day they’ve actually done it:

We at GitHub are honored to be part of the next chapter of npm’s story and to help npm continue to scale to meet the needs of the fast-growing JavaScript community.

For the millions of developers who use the public npm registry every day, npm will always be available and always be free. Looking further ahead, we’ll integrate GitHub and npm to improve the security of the open source software supply chain, and enable you to trace a change from a GitHub pull request to the npm package version that fixed it.

npm is joining GitHub →

Beware when merging Pull Requests with a changed lockfile

When watching a diff that contains a lockfile (say: a yarn.lock for example) on GitHub, GitHub doesn’t always show the differences (see screenshot above) as the changes in such files tend to be quite big. And even if it were to show the changes, does one really take a close look into it? With this in mind, Liran Tal started playing around to create a vector of attack using those lock files.

Take this diff for example:

What becomes clear when you look closer, is that I replaced the original ms npm package to resolve it with my own version, which is stored in my GitHub repository. I should have gotten it from the official npm registry, just as was originally set in the lockfile of the project.

When this pull request gets merged, I inject my malicious version of [email protected] into the code in order to control its behavior during runtime.

In this way, I could introduce a backdoor, alter the logic of the ms module or I could run some postinstall scripts.

To prevent such commits from being merged, you can resort to lockfile-lint which will warn you for such issues.

As an end-user it’s wise to run npm install with --ignore-scripts.

Why npm lockfiles can be a security blindspot for injecting malicious modules →

Wombat Dressing Room, an npm publication proxy on GCP

When automating the publishing of an NPM package, 2FA can get in the way, as you can’t really automate entering a 2FA auth code off a cellphone. Enter Wombat Dressing Room from Google:

With Wombat Dressing Room, rather than an individual configuring two factor authentication in an authenticator app, 2FA is managed by a shared proxy server..

  • You publish to Wombat Dressing Room, and it enforces additional security rules, before redirecting to registry.npmjs.org.
  • Publishes are made from a single npm account with 2FA enabled (a bot account).
  • Publishes can be made using the npm CLI, by making Wombat Dressing Room the default registry (npm config set registry https://external-project.appspot.com).

The Wombat Dressing Room is deployed to Google App Engine. They’ve been using it themselves internally for over a year, in case you were wondering if it is “production ready”.

Wombat Dressing Room Introductory Post →
Wombat Dressing Room Proxy Source (GitHub) →

Use a Github repository branch or commit as a dependency in package.json

Recently I needed to test a branch of a forked GitHub repository inside a project. Instead of cloning the fork and symlinking the package locally, I installed the remote dependency directly into the project.

To achieve I used the following command:

Using NPM:

npm install user/repo.git#branchname

Using Yarn:

yarn add ssh://[email protected]:user/repo.git#branchname

💡 If you’re targeting a specific commit or tag, replace branchname with the commmithash or tagname

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Programmatically add scripts to package.json with npm-add-script

Recently I needed to automate the addition of the addition of a script defined in a package.json‘s scripts section. To do this I used npm-add-script (an older, but still functioning project), along with the aforementioned npx.

For example, to add a script labelled start with the contents webpack-dev-server --config ./config/webpack.config.babel.js --env.MODE=development --open --hot, I use:

npx npm-add-script \
  -k "start" \
  -v "webpack-dev-server --config ./config/webpack.config.babel.js --env.MODE=development --open --hot" \

Using the --force I enforce overwriting of any existing start script.

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Find the cost of adding a npm package to your bundle with BundlePhobia

Ever wondered what the (size) impact of adding an NPM package to your project is? BundlePhobia is a tool that does not only that, it also recommends you other similar packages that have a lesser load.

This thing lets you understand the performance cost of npm install‘ing a new npm package before actually adding it to your bundle.

BundlePhobia →

The Economics of Open Source // Introducing Entropic, a federated package registry

At JSConf EU 2019, CJ Silverio – former CTO at NPM Inc – gave this talk on why a VC-funded private package registry (read: the one ran by NPM Inc) holds many dangers.

The JS package commons is in the hands of a for-profit entity. We trust NPM Inc with our shared code, but we have no way to hold NPM Inc accountable for its behavior. A trust-based system cannot function without accountability, but somebody still has to pay for the servers. How did we get here, and what should JavaScript do now?

At the end of the talk she announced Entropic, a federated package registry for anything; but mostly JavaScript.

Entropic assumes many registries co-existing and interoperating as a part of your normal workflow. All Entropic packages are namespaced, and a full Entropic package spec also includes the hostname of its registry.

Entropic: a federated package registry for anything →

Optimizing JavaScript packages for tree shaking

Geoffrey Dhuyvetters from madewithlove on how authors of (open source) JavaScript packages can optimize their builds for tree shaking:

How do we create a package that exposes both CommonJS & ES modules while making sure we don’t break cross-platform support? Publishing 2 separate packages is an option (e.g. lodash/lodash-es). But there is a nicer, more maintainable option that obviates the need to publish twice. We can provide an extra build step that creates an ES version of our package and links it via package.json.

The package.json links both builds like so:

  "main": "build/cjs/index.js",
  "module": "build/esm/index.js",

Didn’t know you could als provide a module field, similar to name … handy!

Optimizing JavaScript packages for tree shaking →

Stealing Usernames, Passwords, and other (Personal) Data via Browsers and NPM Packages

👋 This post also got published on Medium. If you like it, please give it some love a clap over there.

Late 2016, Stoyan Stefanov published “Oversharing with the browser’s autofill”. It’s an article on stealing personal data using the browsers their form autofill feature. The attack works by leveraging abusing the fact that autocompletion will also complete fields which are visually hidden.

Note: it was only in January 2017 that this type of exploit gained traction, and was accredited to the wrong person (see this ZDNet article for example). As Stoyan points out in his article: it’s been warned about as early since 2013.

If it’s a comfort: it’s not until you enter data in one field and successively choose to autocomplete, that you’re leaking data.


Fast forward to late 2017: In “No boundaries for user identities: Web trackers exploit browser login managers” the autocomplete feature of password managers is abused by rogue advertising scripts.

Since your password manager (and your browser itself) will prefill usernames and passwords, any script loaded can read these out and do whatever they want to with it. Unlike the autocomplete above this kind of leak will happen automatically .At least two advertising scripts have been identified to using this technique to collect usernames.

The only way to prevent this is that browsers return empty strings for autocompleted values when reading them in via input.value,
or at least present a confirm dialog (and pause the JS runtime) until approved.


In “I’m harvesting credit card numbers and passwords from your site. Here’s how.” David Gilbertson notched it up a little:

I can’t believe people spend so much time messing around with cross-site scripting to get code into a single site. It’s so easy to ship malicious code to thousands of websites, with a little help from my web developer friends.

I know, the previous attacks mentioned weren’t XSS attacks, yet one could perform them through after injecting a remote script 😉

All you have to do is write a successful NPM package which others will use. Popular ones are things like logging libraries (*), which have many many downloads. If you then release a version with some rogue code …

(*) Speaking of: my Colored Line Formatter for Monolog has surpassed 250K downloads this week!

Would this kind of hack code be detected easily? Not really. The versions that get published on NPM are compiled and minified versions which are nowhere to be found in the source repo. Above that the compiled code can be obfuscated, so that words like fetch don’t appear in it. And requests performed via dynamically injected links that have a rel="prefetch" attribute set can bypass Content Security Policies.


Yesterday evening there was a small debacle on the NPM front as several packages had gone missing … it was left-pad chaos all over again, albeit for only a short period of time.

One of the packages missing – namely pinkie-promise – is used in eslint, which itself is used just about everywhere. Installing dependencies in React-based apps didn’t work anymore because of this.

By now the issue has been resolved (postmortem here), yet the window between Jan 06, 2018 - 19:45 UTC (identified) and Jan 06, 2018 - 21:58 UTC (resolved) was a very dangerous one. In said window any developer could release (and have released!) packages with the same name. Mostly they were re-publishes of the actual thing, yet one could’ve also published rogue versions such as the ones described above.

NPM is already fighting name squatters by disallowing variants with punctuations and promoting the use of username-scoped packages, but I personally think an extra feat is missing: upon unpublishing of a package (be it by accident or not), its name should be quarantined for 30 days. In that 30 day window no NPM user other than the original one should be able to republish a package having the same name. Additionally there should be an option for the original author to release or transfer a package name to another NPM user.


Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

☕️ Buy me a Coffee ($3)