TidyURLs
Go to Tools
BLOG
The TidyURLsJournal

Practical guides, tutorials, and insights about URLs, SEO, web development, and online marketing. Learn, troubleshoot, and get the most of the web.

Back to the Journal
TidyURLs Journal

npm ci vs npm install: Which Command Should You Use?

Practical insights, clear explanations, and useful ideas for understanding the web.

October 26, 20265 min read6 topics
npm ci vs npm install: Which Command Should You Use?
Explore the details
#npm#Node.js#JavaScript#CI/CD#package-lock.json#DevOps
October 26, 20265 min read

Choosing between npm ci and npm install comes down to whether you want to make dependency changes or reproduce the dependencies already recorded for a project. The distinction matters when a lockfile is out of sync, and it can determine whether a CI build installs the same dependency tree as a developer’s machine.

Key Takeaways

  • Use npm install for everyday development, especially when adding or updating dependencies.
  • Use npm ci in CI to install from the committed lockfile without changing it.
  • npm ci fails if package.json and the lockfile disagree; npm install can resolve the mismatch and update the lockfile.
  • Commit package-lock.json and use compatible npm configuration across local development and CI.

What each command does

Both commands install project dependencies, but they treat the lockfile differently.

Behaviornpm installnpm ci
Main purposeInstall dependencies and support dependency changesClean, lockfile-based installation for automated or clean environments
Lockfile requiredNoYes: a compatible package-lock.json or npm-shrinkwrap.json must exist
If manifest and lockfile disagreeResolves dependencies and may update the lockfileExits with an error
Existing node_modulesReuses or adjusts the directory as neededRemoves it before installing
Writes the lockfileMay write or update itDoes not write package manifests or lockfiles

The lockfile records the resolved dependency versions and related information used for an installation. Committing it lets npm use those recorded resolutions instead of resolving the dependency ranges afresh each time.

When to use npm install

Use npm install during development when you need to install the project’s dependencies or change them. For example, to add a package:

npm install lodash

To add a development dependency:

npm install --save-dev eslint

These commands update the project’s dependency declarations and, when applicable, its lockfile. Review and commit both package.json and package-lock.json so the change can be reproduced by teammates and CI.

Running npm install in a project that already has a lockfile is also a normal way to install dependencies locally. If the lockfile is consistent with package.json, npm uses the locked resolutions. If it is missing or no longer satisfies the manifest, npm resolves dependencies and can update the lockfile.

When to use npm ci

Use npm ci when you want a clean install based on the project’s committed lockfile, particularly in a CI job:

npm ci
npm test

Unlike npm install, npm ci removes an existing node_modules directory and installs the project dependencies anew. It does not update package.json or the lockfile. If the lockfile is missing or does not match the manifest, the command fails rather than repairing the files.

This makes npm ci useful for checking the dependency state represented by a commit. It is not a guarantee that every environment behaves identically: npm version, operating system, architecture, configuration, and dependency install scripts can affect the result. Use a consistent Node.js/npm setup where possible, and don’t treat a lockfile as a substitute for testing across your supported environments.

What happens when package.json and package-lock.json disagree?

Suppose package.json allows a package version range that the lockfile does not record, or a dependency declaration was changed without regenerating the lockfile.

With npm install, npm resolves dependencies to satisfy the manifest and can update package-lock.json. Review the resulting diff: a change to one dependency can affect other resolved versions too.

With npm ci, npm stops and reports that the manifest and lockfile are not in sync. Fix the mismatch in a development environment, then commit the updated files:

npm install
# Review package.json and package-lock.json
npm test
git diff -- package.json package-lock.json

Do not make CI run npm install just to hide this error. A CI failure is a useful signal that the committed dependency declarations and lockfile need attention.

A practical local-to-CI workflow

For a dependency change, use npm install, test the change, and commit the manifest and lockfile together. For a clean local check or an automated build, run npm ci from a checkout that contains those committed files.

A basic CI job can run:

npm ci
npm test
npm run build

Make sure the job uses the expected Node.js and npm versions. If the lockfile was created using settings that affect dependency resolution—such as legacy-peer-deps or install-links—use the same settings for npm ci. One way to share project-level npm settings is to commit an appropriate .npmrc; avoid putting credentials or secrets in a committed file.

Common Mistakes

  • Using npm ci to add a dependency. It installs the existing locked project; use npm install <package> to change dependencies.
  • Treating npm ci as a lockfile repair command. It deliberately fails on a mismatch. Update the lockfile with npm install and commit the result.
  • Leaving the lockfile out of version control. Without a committed lockfile, CI cannot reproduce the dependency resolutions recorded by the project.
  • Using different dependency-resolution options locally and in CI. Configuration differences can make the lockfile unusable with the CI command. Keep relevant settings consistent.
  • Assuming a successful install proves the build is portable. Install scripts and platform-specific dependencies can vary; run the tests and build in the environments you support.

Best Practices

  1. Commit package-lock.json for applications and other projects where repeatable installs matter.
  2. Use npm install to add or change dependencies, and review its lockfile diff before committing.
  3. Use npm ci in CI and other clean-install checks so lockfile inconsistencies are surfaced.
  4. Keep Node.js, npm, and project npm configuration consistent between development and automation.
  5. When npm ci fails, fix and commit the dependency mismatch rather than bypassing the check.

Conclusion

Use npm install to work on dependency changes; use npm ci to install the committed dependency tree cleanly. The lockfile is central to that workflow: keep it in sync with package.json, commit both when dependencies change, and let CI report mismatches instead of silently rewriting them.

References