Skip to content
Latchkey

npm ci: Usage, Options & Common CI Errors

The deterministic install built for CI pipelines.

npm ci installs exactly what package-lock.json specifies, deleting node_modules first for a clean, reproducible tree. It is faster and stricter than npm install - and it is what you should run in CI.

What it does

Requires both package.json and package-lock.json (or npm-shrinkwrap.json). Deletes any existing node_modules, then installs the exact versions in the lockfile. It never writes to package.json or the lockfile, and it errors out if the two are out of sync.

Common usage

.github/workflows/ci.yml
npm ci                  # clean install from the lockfile
npm ci --omit=dev       # production install, skip devDependencies
npm ci --ignore-scripts # skip lifecycle scripts (faster, safer)

Common CI error: lockfile out of sync

CI fails with "npm error code EUSAGE / npm ci can only install packages when your package.json and package-lock.json are in sync". Someone edited package.json without regenerating the lockfile. Fix it by running npm install locally, then committing the updated package-lock.json - do not switch CI to npm install to paper over it.

Terminal
# locally, regenerate and commit the lockfile:
npm install
git add package-lock.json && git commit -m "sync lockfile"

Key options

FlagEffect
--omit=devSkip devDependencies (production install)
--ignore-scriptsSkip lifecycle scripts
--no-auditSkip the audit step (faster CI)
--prefer-offlineUse cache before hitting the registry

Using this in CI

Node tooling on a runner differs from your machine in three ways that matter: CI=true is set, there is no TTY, and the Node major may not be the one you develop on.

  • Pin the Node major with setup-node and in engines. Native modules resolve different prebuilt binaries per major.
  • CI=true changes behaviour in several tools, most often by promoting warnings to errors or disabling interactive prompts.
  • Commands that expect a TTY will hang. Pass the non-interactive or --yes flag explicitly.
  • Use npm exec or node_modules/.bin rather than assuming a globally installed binary is on PATH.

Frequently asked questions

npm ci: Usage, Options & Common CI Errors?
npm ci installs exactly what package-lock.json specifies, deleting node_modules first for a clean, reproducible tree. It is faster and stricter than npm install - and it is what you should run in CI.
What it does?
Requires both package.json and package-lock.json (or npm-shrinkwrap.json). Deletes any existing node_modules, then installs the exact versions in the lockfile. It never writes to package.json or the lockfile, and it errors out if the two are out of sync.
Common CI error: lockfile out of sync?
CI fails with "npm error code EUSAGE / npm ci can only install packages when your package.json and package-lock.json are in sync". Someone edited package.json without regenerating the lockfile. Fix it by running npm install locally, then committing the updated package-lock.json - do not switch CI to npm install to paper over it.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card