How can I use npm ci instead of npm install?

We’re working through some issues where some of our JS contributors are committing a package.json update for our deployed app without also updating package-lock.json. This presents problems when trying to create reproducible builds with deterministic dependencies. Most recently some of our builds have failed on Netlify but work fine locally (while silently overwriting package-lock.json and creating a dirty git tree). I want broken builds to break in CI, and automated builds should absolutely never overwrite the lockfile.

I’ve noticed that JS builds without a yarn.lock file automatically run npm install before turning over to the build command in my netlify.toml file. The yarn builds seem to run yarn install. Neither of these are correct. Both tools have ways to pull deps solely from their respective lockfiles and verify that the package.json is compatible with the locks. If the lockfiles don’t match package.json, the build will fail. For npm the correct invocation is npm ci and for yarn it appears to be yarn install --frozen-lockfile.

Is there any way to run npm ci instead of npm install, or otherwise have Netlify skip the install step so I can run npm ci myself without the automatic install step screwing up my checkout?

Hi Jeff & welcome to our community!

Our build system isn’t super flexible, but that pattern works for most folks and to change it would break builds on thousands of sites. Fortunately, you can work around it in a few ways:

  1. don’t have a package.json, package-lock.json or yarn.lock in the root of your repo (or in your base directory if you have one set). Then we won’t automatically run anything.
  2. you could instead “fake us out” and use something like $YARN_FLAGS set to --dry-run to make the auto-install a no-op, or maybe you want the --package-lock-only option to npm to create the lock, which you can then use? Not sure exactly what will best solve your use case. There’s a similar $NPM_FLAGS. You can set those in our UI, or in the netlify.toml config file.

Then you can run npm ci or yarn ci or whatever build command you like, in whatever way you like. Note that if you want to use anything other than npm - you’ll need to first INSTALL it- we have a VERY bare build environment by default, so you’ll need npm i yarn && yarn ci if you use yarn.

Note that unless you do some manual dependency caching at that point, you will have also opted out of that, since we run those installation commands with a special cache directory as shown here:

…so you might want to do some explicit cache management using a package like https://www.npmjs.com/package/cache-me-outside . That isn’t officially supported, but works well for many folks.

Sorry I don’t have a more direct way to accomplish your goal today. It’s interesting that this is the first we’ve heard of this need (not of the desire not to auto-run yarn/npm, but to use npm ci instead of npm install. Perhaps what you really need is a