👉 You might also be interested in my NodeJS notes, or notes on building an NPM package.
💡 I highly recommend a version manager, like
asdf
, for managing multiple versions of NPM and Node on the same system. I also have a separate cheatsheet on using asdf.
Upgrading NPM itself
- Check version with
npm -v
- Upgrade depends on OS - full details
- *nix -
npm install -g npm@latest
ornpm install -g npm@next
- Windows: Use this tool
npm install --global --production npm-windows-upgrade
npm-windows-upgrade --npm-version latest
ornpm-windows-upgrade
- If any of the above fail:
- Make sure you are in elevated prompt
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
- If still failing, you might need to upgrade Node - [link]https://nodejs.org/en/download/)
- *nix -
How to Run NPM Commands From a Different Directory / Changing Directory for Commands
To run npm commands from a directory outside of where the package.json
file resides, such as from a parent directory, you can use the --prefix
CLI argument to set the directory where the command should be executed. This works for both standard npm commands:
npm run --prefix ./other-dir dev
as well as npx
commands:
npx --no-install --prefix ./other-dir prettier --version
Init
npm init
, or without the step-by-step questions, npm init -y
NPM Install / Installing Packages
Some useful install flags - see full list here
Flag | Full Flag | Description |
---|---|---|
-g | --global | Save globally instead of into local project |
NA | --link | Link globally installed packages into local project |
-P | --save-prod | Save into dependencies section. Default |
-D | --save-dev | Package will show in devDependencies |
-O | --save-optional | Package will show in optionalDependencies |
NA | --no-save | Does not save to package.json at all! |
Remember to wrap semver ranges with quotes when using with install in a CLI. E.g.
npm install fs-extra@">=0.3.0 <0.3.2"
Install a very specific version of a package (from CLI)
You can actually use similar syntax as a package.json
file - e.g. tslint@^5.0.0
.
- NPM
npm install {packageName}@{semVerPattern}
- Yarn
yarn add {packageName}@{semVerPattern}
Install a Github Repository as a dependency
All of these should work (NPM):
npm install git+https://github.com/{USER}/{REPO}.git
npm install {USER}/{REPO}
- Or,
npm install {USER}/{REPO}#branch
- Or,
npm install github:{USER}/{REPO}
Plus, variations with a trailing #{COMMIT_HASH}
or #semver:{SEMVER}
.
🚨 Warning: NPM only supports installing repos that have a root
package.json
file; otherwise you will get an error:npm ERR! premature close
. The only workaround is to use Yarn, manually pull in the repo via some shell scripting, use a package that automates the install process (e.g. napa), or use git submodules. Or usedegit
as theinstall
command. Or, you could fork the entire repo and add apackage.json
file yourself!
For all of the available install commands and flags, don't forget to read the docs for NPM, or Yarn.
Always Installing devDependencies
By default, NPM will not install devDependencies
if NODE_ENV
is set to production
. Certain PaaS systems will also do this by default in their build step, like DigitalOcean's App Platform for example.
There are many different workarounds enumerated in the responses to this StackOverflow.
The most common approaches are:
- Set
NODE_ENV
manually before running install, then set backNODE_ENV=build && npm ci && NODE_ENV=production
- Install the dev dependencies separately, as an additional step after the main install
npm install && npm install --only=dev
Re-install a package, overwriting local modifications
Occasionally, the easiest way to debug an issue with a 3rd party library is to just open up node_modules
and edit the raw package distributable files. Once you are done, you will want to reset the folder, getting rid of your local edits.
This is actually how npm install
works by default. Just make sure you are using npm install {pkg}
and not npm update {pkg}
; update
will not override the local changes if the version has not changed.
Viewing and Exploring the Contents of an NPM Package
Aside from installing locally and then manually exploring the files added to your computer under node_modules
, you can also explore the contents of a published NPM package with some online tools:
- UNPKG
- Sample Options:
unpkg.com/:package@:version/:file
(specific file)unpkg.com/:package@:version/
(directory listing)
- For example: unpkg.com/react/
- Sample Options:
- runpkg
- Similar options to UNPKG, and you should be able to just add
r
at the beginning of aunpkg
URL to redirect - Example: runpkg.com/react/
- Similar options to UNPKG, and you should be able to just add
Semver
- Calculator and cheatsheet - semver.npmjs.com
- Devhints cheatsheet
Updating release versions
You can use npm version {semVerString}
to set a new version. This will update package.json
, package-lock.json
, and npm-shrinkwrap.json
.
A helpful thing to remember is that, without any other arguments, this does a lot of automatic stuff you might not want:
- Adds a new git commit with automated message
- Use custom with
-m
arg
- Use custom with
- Add a new git tag, and points it at the auto commit
- Use
--no-git-tag-version
to disable
- Use
- Updates the npm files (as mentioned above)
- Runs
preversion
,version
andpostversion
underscripts
.
Update version without tagging OR adding commit
Use the --no-git-tag-version
arg, or git-tag-version=false
Auto version bump
If you don't want to manually type out a version string, you can just auto bump the version, so long as you are using a valid semVer in your npm files. Use npm version {incrementTarget}
where {incrementTarget}
is one of:
- major
- minor
- patch
- premajor
- preminor
- prepatch
- prerelease
Including the Lockfile
A common question devs have about projects that use a package manager is "should I commit the lockfile to version control?". In general, yes, especially for apps.
There are several good reasons to commit a lockfile:
- Reproducibility: A lockfile, as its name implies, locks the version of each dependency (and sub-dependency) to the specific version from your latest install command, even if your
package.json
has a loose semver range (like*
, or^#.#.#
)- No more "works on my machine" arguments that are caused by
npm install
being run on different days and grabbing different dependencies - You can be sure that your CI, local PC, and other devs all have the exact same version of all dependencies
- No more "works on my machine" arguments that are caused by
- Security: Although there are also some security risks with lockfiles themselves, used correctly and with care, there is some additional security afforded by their use; if you are locked to a good version of a package, and that author gets hacked and starts publishing a bad version, your build pipeline won't be affected unless somebody manually updates to that version and commits the lockfile.
- There are also multiple security tools and systems that can automatically scan lockfiles for known security issues; this is now baked into Github, for example.
Yarn does a great job of summarizing these benefits in this article. The
actions/setup-node
GitHub action also has a nice summary.
However, there is also a very specific argument against committing lockfiles, if you are building a NPM package. The reason being that, if your project is a package and is being installed as a dependency, the lockfile is not considered, only the package.json file is.
The reason why this is problematic, is that you can actually end up with that "works on my machine" issue, but with an added false sense of security; when you are developing your package locally, the lockfile is respected and everything works with the exact versions you need, but when a project that consumes your package installs it as a dependency, it just grabs whatever matches your package.json
semver settings, which might allow for a dependency version that breaks your code. Sindre Sorhus, who is one of the most prolific NPM package creators, summarizes the issue here.
In these instances, it might be better to omit the lockfile, and instead very narrowly define the semver in your package.json
, perhaps even specifying an exact version.
Exploring Packages
List all installed packages
Courtesy of jkomyno
# NPM
npm list -g --depth 0
# Yarn
yarn global list
Find the binary of a given package
Many devs already know you can use npx {packageName}
to run with a preference for using local binaries before downloading and executing a global install, but what about locating the actual binary path?
- NPM
- All local binaries (nearest bin dir) (echo path):
npm bin
- Note: This is where npm will install binaries if called from the current working directory, not necessarily where they are already installed.
- Specific binary: you can use variable substitution with
npm bin
if you really need the path, otherwise just usenpx
- All local binaries (nearest bin dir) (echo path):
- Yarn
- Pretty similar to NPM (above)
- All local binaries (echo path):
yarn bin
- This has the same disclaimer as
npm bin
- This has the same disclaimer as
- Specific binary (echo path):
yarn bin {package}
- Run a specific binary:
yarn {package}
- Unlike npm, yarn does not require something like
npx
be used to run against a local command
- Unlike npm, yarn does not require something like
Find top level package that is using another
If we have package {top-level} that is using {sub-depend}, but we don't know which one is requiring it - all we know is that one of our top packages is using "sub-depend", we can find out which one it is by using:
# NPM - Newer methods (v7+)
npm explain {sub-dependency-name}
# alias to above, also v7+
npm why {sub-dependency-name}
# NPM - Old method
npm ls {sub-dependency-name}
# Yarn
yarn why {sub-dependency-name}
Get information about packages
npm ls
can show a list of locally installed packages, or info about why a specific package is included- Use
npm explain {package}
for a bottoms-up view on why a specific package is included
- Use
npm view
(or alias ofnpm info
) can be used to get info about both local and remote packagesnpm view {package}
will show latest infonpm view {package}@{ref}
will show version-specific info- You can pass a property from
package.json
to view even more specific information about a package- E.g.
npm view react-native@0.72.0 engines
will output{ node: '>=16' }
- E.g.
List versions
npm -version
Get the version of a package
NPM - Getting the version of a package
npm list {packageName}
Yarn - Getting the version of a package
yarn list --pattern {packageNameOrPattern}
Or...
yarn list | grep {packageNameOrPattern}
Or...
yarn global list --pattern {packageNameOrPattern}
Updating / upgrading packages used in package.json
- NPM
- You can use
npm update
to pull in updated packages (will also update your package-lock.json automatically)- E.g.
npm update typescript
- E.g.
- You can use
npm outdated
to see what yourpackage.json
is requesting VS what is published- Good to use this to double-check after running
npm update
, sincenpm update
requests based on yourpackage.json
semver rules, not necessarily what is newest
- Good to use this to double-check after running
- For upgrading to the absolute latest, ignoring
package.json
, there is no built-in command (unlike Yarn)The easiest way to do it by hand, is to edit thepackage.json
file to have*
as the semver for any dependency you want to have updated to the latest, and then runnpm update
again.Since npm knowns*
is invalid, it will update and then overwrite the entry- Nope! This cannot be relied on in newer versions of NPM.
- One manual option is to call
npm install PACKAGE_NAME@latest
for each dependency you want updated - For an automated / interactive 3rd party solution, you could check out one of these:
- npm-check-updates
- Check outdated:
- NPX:
npx npm-check-updates
- Binary:
ncu
- NPX:
- Upgrade package file (non-interactive):
- NPX:
npx npm-check-updates -u
- Binary:
ncu -u
- NPX:
- Upgrade package file (interactive)
- NPX:
npx npm-check-updates -u -i
- Binary:
ncu -u -i
- NPX:
- ^ You still need to run
npm install
after any package updates, to actually update lockfile & node_modules
- Check outdated:
- https://www.npmjs.com/package/npm-check
- You can use
-g
for global packages
- npm-check-updates
- You can use
- Yarn:
- Upgrade to latest specified by package.json:
yarn upgrade
- Same as above, but interactively:
yarn upgrade-interactive
- Upgrade to absolute latest, ignoring package.json (for example, major version bump):
yarn upgrade-interactive --latest
- You can use
yarn outdated
to see what yourpackage.json
is requesting VS what is published- See notes above on
npm outdated
, since this works similarly
- See notes above on
- Upgrade to latest specified by package.json:
Yarn Timeouts
If you ever get the error with yarn
info There appears to be trouble with your network connection. Retrying...
, and you are 100% sure your internet connection is fine, here are some other things to try
- Flush your local DNS cache, double check connection, etc.
- Increase timeout:
yarn add --network-timeout 1000000 {package}
- Make sure there are no proxies configured, and all config info is correct:
npm config list
yarn config list
- Clear cache:
yarn cache clean
and thenyarn
- Make sure the repository you are using is operational:
- NPM: status.npmjs.org
- If you have left yarn repository setting at default, try explicitly setting it to NPM:
yarn config set registry "https://registry.npmjs.org"
- Try things from these threads:
- Try deleting your global yarn.lock file
- Location might differ:
C:\Users\{USER}\AppData\Local\Yarn\Data\global\yarn.lock
- Location might differ:
- Try running with
--verbose
flag, to see if you see anything unusual in the log - Try completely resetting local package store -
rm -rf node_modules
,rm yarn.lock
,yarn
- This was the only thing that worked for me at one point
- Consider upgrading (if you haven't already) to
v2.*
of Yarn, instead ofv1
- However, this comes with its own set of issues / concerns
How to deal with nested sub-dependency versions
A somewhat common issue is trying to force a direct dependency (listed under dependencies
or devDependencies
in package.json) to use a specific version of their dependency.
These are sometimes called sub-dependencies, or transitive dependencies
This is not something you normally dictate - it is normally handled automatically by NPM or Yarn - but sometimes you might want to force a certain sub-dependency version due to a vulnerability; for example, if you use my-dependency
which has a nested dependency of my-sub-depend
locked at v0.0.1
, which has a severe vulnerability patched in v0.0.2
.
There are multiple ways to approach this, and on of the best starting spots is this S/O Question.
- NPM
- NEW in 2022 (npm version
v >= 8.3
): Use the overrides section ofpackage.json
- Use Shrinkwrap file
- Run
npm shrinkwrap
- Manually edit the auto-created
npm-shrinkwrap.json
file- Use Semver targeting to force the new version you want
- Run
npm install
again
- Run
- Use an automated solution, like
npm-force-resolutions
- This lets you use the
package.json -> resolutions
approach, that natively works with Yarn (see below)
- This lets you use the
- NEW in 2022 (npm version
- Yarn
- Yarn is way easier to use overrides with, in comparison to NPM
- Just add
resolutions
object topackage.json
with overrides
💡 Tip: For both NPM and Yarn, another option to upgrade a sub-dependency if the top-level package requesting it is using a loose(r) semver, is to delete the entry from the
lock
file, and then re-run the package management command.
💡 To check for unmet peer dependencies,
npm ls
is a command that works
When in doubt and messed up beyond repair...
npm cache clean -force
When REALLY messed up
rm -rf node_modules
npm cache clean -force
npm install
Installing peer-dependencies
Many packages, especially lint configs, will require other dependencies (peer dependencies) but will not install them automatically.
You can list peer dependencies needed by a package by using:
# NPM
npm info "{package}" peerDependencies
You could manually figure out what's needed (by using npm info
, or npm ls
once installed) and manually install one by one, or use a tool like install-peerdeps
.
If you are just trying to check if you have any unmet peer dependencies, you can use the npm ls
command.
🚨 Yarn does not currently auto-install peer-dependencies; you have to manually do it yourself.
install-peerdeps Usage
Installation:
# NPM
npm install -g install-peerdeps
# Yarn
yarn global add install-peerdeps
Usage:
install-peerdeps --dev {package}
# OR
install-peerdeps {package}
# OR
install-peerdeps <package>[@<version>]
Another option is the
install-peers-cli
packageyarn add --dev install-peers-cli yarn install yarn run install-peers --force-run
Using global modules / packages
You can use globally installed packages by taking advantage of link
- which basically just symlinks from the global folder to your project directory. Once something is installed globally, you can simply run npm link {packageName}
in the directory where you want to be able to access it.
WARNING: The much preferred way to do this is with
npx
, which will use your project's dependency first, if it has it.
Currently, Yarn will allow linking of dev packages (e.g.
yarn link
in dev,yarn link {name}
in test), but tends to have issues with globally installed versions (GH issue).
NPM Install Errors
gyp related errors:
- "No prebuilt binaries found"
- There is probably a dependency that was built using C++ or other codebase and is missing a prebuilt binary for your versions of node/ABI#. Check your ABI and compare against what is hosted as a prebuilt binary.
- If you can't find a prebuilt to use, just build yourself (check dependency's package.json and .gyp for details). You will probably also need build tools installed, depending on OS:
npm install --global --production windows-build-tools
- There is probably a dependency that was built using C++ or other codebase and is missing a prebuilt binary for your versions of node/ABI#. Check your ABI and compare against what is hosted as a prebuilt binary.
- General build errors ("MSBuild", etc)
- Make sure that you have build tools installed (see above)
- Make sure built-tools install WORKED
- Make sure to run as Admin
- Check log, and if necessary, manually run the installer it downloads
- Make sure built-tools install WORKED
- You can switch what version of MSVC you are targeting:
- For example:
npm config set msvs_version 2015 -g
- For example:
- Try to get Node to use a prebuilt-binary instead of building from scratch
- Check the log to see why node is trying to rebuild/build
- For example, is a firewall blocking the binary download?
- Some install scripts will let you specify a binary source URL
- A quick hack if you can find a pre-built binary to download, is to save it to the corresponding
npm-cache
folder, and then runnpm rebuild {packageName}
before trying to re-install.- You should see
Cached binary found at ...
if this trick worked - Found via this comment
- You should see
- Check the log to see why node is trying to rebuild/build
- Make sure that you have build tools installed (see above)
List tasks
npm run
See package release history
npm view {package} time