Why does `package-lock.json` causes a failure in a docker container build when `npm install`?

docker, node.js, npm, package-lock.json

Solution

From your question:

Note: npm install works fine on my local machine, just fails in docker container

If you are using `npm install`, you are not sure to have the same version of dependencies.

For having a reproducible environment, without unexpected issues because of different version of dependencies, you'd rather use `npm ci` (clean-install):

This command is similar to npm-install, except it’s meant to be used in automated environments such as test platforms, continuous integration, and deployment – or any situation where you want to make sure you’re doing a clean install of your dependencies. It can be significantly faster than a regular npm install by skipping certain user-oriented features. It is also more strict than a regular install, which can help catch errors or inconsistencies caused by the incrementally-installed local environments of most npm users.

In short, the main differences between using npm install and npm ci are:

- The project must have an existing package-lock.json or npm-shrinkwrap.json.

- If dependencies in the package lock do not match those in package.json, npm ci will exit with an error, instead of updating the package lock.

- npm ci can only install entire projects at a time: individual dependencies cannot be added with this command.

- If a node_modules is already present, it will be automatically removed before npm ci begins its install.

- It will never write to package.json or any of the package-locks: installs are essentially frozen.

A Fabian Gander's article gives further clarification about the `npm install` and `npm ci` tools and provides advice on when to use each one. The below table is from that source:

  cases                                | npm install | npm ci
 --------------------------------------|-------------|-------------
  needs package.json                   | no          | yes
  needs package-lock.json              | no          | yes
  installs from package.json           | yes         | no
  installs from package-lock.json      | no          | yes
  compares both                        | no          | yes
  updates loose package versions       | yes         | no
  updates loose dependencies           | yes         | no
  writes to package.json               | yes         | no
  writes to package-lock.json          | yes         | no
  deletes node_modules before install  | no          | yes
  used for installing separate package | yes         | no
  should be used on build systems / CI | no          | yes
  can be used for development          | yes         | yes
  reproducible installs                | no          | yes

This is why package-lock.json is there, to be available for tools like `npm ci`.

After having a reproducible environment, if this doesn't fix your issue, you need to keep investigating, but IMO it should be the first step.

Problem

There are a lot of people online asking this same question in different ways but there is no clear answer. Can anybody understand enough to explain why a `docker build` fails when `package-lock.json` file exists in the application, but runs successfully when it is not? Seemingly it is related to npm but it is not clear. Everybody says delete the `package-lock.json`, but it is there for a reason. Note: `npm install` works fine on my local machine, just fails in docker container. If I have this Dockerfile: ``` # First Stage: Builder FROM node:13.12.0-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build ``` And run this: ``` docker build -t container-tag ./ ``` I get this: ``` npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/eventsource-c2615740/example/index.html' npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/eventsource-c2615740/example/sse-client.js' npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/react-router-a14663ae/README.md' ``` But this Dockerfile will run successfully: ``` # First Stage: Builder FROM node:13.12.0-alpine AS build WORKDIR /app COPY package.json ./ #<-------- note that there is no star here RUN npm install COPY . . RUN npm run build ```

Original source