All guides

LEARN \u00b7 DEBUGGING GUIDE

npm install works locally but fails in CI: how to debug it

You run `npm install` locally — it works. CI runs the same command — it fails with native module errors, missing Python, or lockfile conflicts. Your local `node_modules` is hiding problems.

BeginnerCI/CD debugging

What this usually means

Your local machine has a warm `node_modules` directory with cached builds. Native modules (like `bcrypt`, `sharp`, `node-sass`) were compiled for your OS and architecture long ago. CI starts from a clean slate — no cache, no build tools, possibly a different OS or CPU architecture. The install fails because the environment lacks the toolchain needed to compile native addons. Alternatively, your `package-lock.json` is out of sync with `package.json` because you added a dependency without running `npm install` to regenerate the lockfile. Locally, npm might silently fix this, but `npm ci` in CI strictly enforces lockfile consistency.

( 01 )Fast diagnosis

The first ten minutes \u2014 establish facts before touching code.

  • 1Check the CI log for the first error. Is it `node-gyp`? `python not found`? `make: command not found`?
  • 2Compare `npm install` vs `npm ci` behaviour. Most CI pipelines use `npm ci` which requires a clean, up-to-date lockfile.
  • 3Check if `package-lock.json` is committed and matches `package.json`. Run `npm install` locally and see if the lockfile changes.
  • 4Check if the CI runner OS matches your local OS. Native modules compiled for macOS will not work on a Linux CI runner.
  • 5Check if optional dependencies are causing failures. Some packages have optional native deps that fail on unsupported platforms.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchCI pipeline config — install command, Node version, OS image
  • searchCI job log — first error from the install step
  • search`package.json` vs `package-lock.json` — are they in sync?
  • searchDependencies with native modules — `bcrypt`, `sharp`, `node-sass`, `canvas`, `puppeteer`
  • searchCI runner image documentation — pre-installed build tools
  • search`.npmrc` or `.yarnrc` — registry config, platform-specific settings
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningNative module needs `node-gyp` but CI runner lacks Python, make, or a C++ compiler
  • warning`package-lock.json` is out of date — `npm ci` rejects it but `npm install` locally auto-fixes
  • warningCI runner is a different OS or CPU architecture (e.g. macOS vs Linux, x64 vs arm64)
  • warningA package requires a specific Node version and CI runs a different one
  • warningOptional dependency fails to install and the error is not handled
  • warningA dependency is listed in `devDependencies` but CI runs with `--production` flag
  • warningPrivate package registry is not accessible from CI (missing `.npmrc` with auth token)
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildRun `npm ci` locally instead of `npm install` — this simulates the CI environment on a clean slate
  • buildAdd required build tools to the CI config: `sudo apt-get install build-essential python3` for Linux runners
  • buildCommit `package-lock.json` and keep it in sync — run `npm install` after every dependency change
  • buildUse `--ignore-scripts` temporarily to identify if the failure is in a postinstall script
  • buildPin the CI runner OS to match the target deployment environment (usually Linux)
  • buildAdd a `.npmrc` with the auth token for private registries as a CI secret
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedPush a commit. CI install step should pass.
  • verifiedDelete `node_modules` locally and run `npm ci`. It should succeed.
  • verifiedRun `npm ci` in a Docker container matching the CI image. It should succeed.
  • verifiedCheck that `package-lock.json` has no uncommitted changes after `npm install`.
  • verifiedVerify native modules build correctly on the CI runner OS.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningRunning `npm install` instead of `npm ci` in CI — `npm ci` is faster and stricter
  • warningNot committing `package-lock.json` to the repository
  • warningAdding build tools globally on the CI runner instead of declaring them in the CI config
  • warningUsing `--force` or `--legacy-peer-deps` to paper over dependency conflicts
  • warningAssuming `node_modules` from a previous CI run is clean enough to reuse