Joshua's Docs - NPM Cheatsheet and Assorted Notes

👉 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 or npm install -g npm@next
    • Windows: Use this tool
      • npm install --global --production npm-windows-upgrade
      • npm-windows-upgrade --npm-version latest or npm-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/)

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
  • 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 use degit as the install command. Or, you could fork the entire repo and add a package.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 back
    • NODE_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/
  • runpkg
    • Similar options to UNPKG, and you should be able to just add r at the beginning of a unpkg URL to redirect
    • Example: runpkg.com/react/

Semver

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
  • Add a new git tag, and points it at the auto commit
    • Use --no-git-tag-version to disable
  • Updates the npm files (as mentioned above)
  • Runs preversion, version and postversion under scripts.

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
  • 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 use npx
  • Yarn
    • Pretty similar to NPM (above)
    • All local binaries (echo path): yarn bin
      • This has the same disclaimer as npm bin
    • 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

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
  • npm view (or alias of npm info) can be used to get info about both local and remote packages
    • npm view {package} will show latest info
    • npm 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' }

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
    • You can use npm outdated to see what your package.json is requesting VS what is published
      • Good to use this to double-check after running npm update, since npm update requests based on your package.json semver rules, not necessarily what is newest
    • 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 the package.json file to have * as the semver for any dependency you want to have updated to the latest, and then run npm 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
          • Upgrade package file (non-interactive):
            • NPX: npx npm-check-updates -u
            • Binary: ncu -u
          • Upgrade package file (interactive)
            • NPX: npx npm-check-updates -u -i
            • Binary: ncu -u -i
          • ^ You still need to run npm install after any package updates, to actually update lockfile & node_modules
        • https://www.npmjs.com/package/npm-check
        • You can use -g for global packages
  • 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 your package.json is requesting VS what is published
      • See notes above on npm outdated, since this works similarly

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 then yarn
  • Make sure the repository you are using is operational:
  • 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
  • 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 of v1
    • 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 of package.json
    • Use Shrinkwrap file
      1. Run npm shrinkwrap
      2. Manually edit the auto-created npm-shrinkwrap.json file
        • Use Semver targeting to force the new version you want
      3. Run npm install again
    • Use an automated solution, like npm-force-resolutions
      • This lets you use the package.json -> resolutions approach, that natively works with Yarn (see below)
  • Yarn
    • Yarn is way easier to use overrides with, in comparison to NPM
    • Just add resolutions object to package.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

https://www.npmjs.com/package/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 package

yarn 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

  • "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
  • 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
    • You can switch what version of MSVC you are targeting:
      • For example: npm config set msvs_version 2015 -g
    • 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 run npm rebuild {packageName} before trying to re-install.
        • You should see Cached binary found at ... if this trick worked
        • Found via this comment

List tasks

npm run

See package release history

npm view {package} time

Markdown Source Last Updated:
Tue Apr 30 2024 05:18:36 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Tue Aug 27 2019 07:54:31 GMT+0000 (Coordinated Universal Time)
© 2024 Joshua Tzucker, Built with Gatsby
Feedback