← Back to Articles         
When running npm install, will it use package-lock.json or package.json?

When running npm install, will it use package-lock.json or package.json?

Published on 10 Nov 2026 5 min read React
React Fundamentals

package.json VS package-lock.json

When you run:

npm install

npm uses both package.json and package-lock.json, but they have different roles.

package.json — What dependencies does the project need?

It declares the dependencies and acceptable version ranges.

For example:

"dependencies": {
  "react": "^19.1.0",
  "react-dom": "^19.1.0"
}

The ^ means npm can potentially use a compatible newer version, such as 19.2.x, rather than being restricted to exactly 19.1.0.

package-lock.json — Which exact versions should be installed?

The lock file records the exact dependency versions and their dependency tree that npm previously resolved.

For example, conceptually:

react
  → 19.1.0

react-dom
  → 19.1.0

some-package
  → 3.2.1

This makes installations reproducible across different machines.

What happens with npm install?

If both files exist:

npm install
     │
     ├── Read package.json
     │      ↓
     │   What dependencies are required?
     │
     └── Read package-lock.json
            ↓
        Which resolved versions?
            ↓
        Install dependencies

So the short answer is:

package.json defines what you need; package-lock.json records the exact dependency versions npm resolved.


Important distinction

If you run:

npm install axios

npm updates:

package.json
package-lock.json

If you run:

npm install

in an existing project with a valid lock file, npm generally installs according to the lock file while respecting the dependency requirements in package.json.

For CI/CD or a production deployment, you will often see:

npm ci

instead. npm ci is specifically designed for clean, reproducible installations and requires the lock file.

What is npm ci?

npm ci means Clean Install.

The easiest way to understand it is to compare it with npm install.

npm install

Used mainly during development.

npm install

It looks at:

package.json
      +
package-lock.json
      ↓
Install dependencies

It can also update package-lock.json if the dependency information needs to be changed.


npm ci

Used mainly for CI/CD and clean installations.

npm ci

It uses the existing:

package-lock.json

to install the exact dependency versions recorded in the lock file.

package-lock.json
      ↓
Exact versions
      ↓
Clean installation
      ↓
node_modules/

Before installing, npm removes the existing node_modules folder.


Simple Example

Suppose your package.json says:

"dependencies": {
  "react": "^19.0.0"
}

The ^ allows compatible versions.

Your package-lock.json might record:

react → 19.0.2

If you run:

npm install

npm resolves dependencies according to package.json and the lock file, and the lock file can be updated if needed.

If you run:

npm ci

npm says, essentially:

"Don't resolve new dependency versions. Give me exactly what is recorded in package-lock.json."

So you get:

react → 19.0.2

Why is npm ci useful in CI/CD?

Imagine your team has 5 developers and a build server.

Without a lock file, dependency resolution could potentially produce different versions at different times.

With:

npm ci

the build server installs the exact dependency tree recorded in package-lock.json.

Developer 1 ─┐
Developer 2 ─┤
Developer 3 ─┼── package-lock.json
Developer 4 ─┤         ↓
Developer 5 ─┤     npm ci
              │         ↓
              └── Same dependency versions

This makes CI/CD builds much more reproducible.


Important Difference

npm install npm ci
Normal development CI/CD / clean builds
Uses package.json + lock file Requires lock file
Can modify package-lock.json Does not update lock file
Doesn't require deleting node_modules first Removes node_modules first
Can resolve dependency changes Installs locked versions

Remember this

npm install
    ↓
"I am developing the application."
    ↓
Install/update dependencies
npm ci
    ↓
"I am building/testing an existing project."
    ↓
Give me exactly what package-lock.json specifies.

For your React + Vite project, you'll normally use:

npm install
npm run dev

During a CI/CD pipeline, you would commonly use:

npm ci
npm run build

ci = clean install, using the lock file exactly.

When running npm install, what will happen if the lockfile has version 6.0.0 and the package.json file has 7.5.0?

The key is that npm does not blindly take the version from package.json or the lock file. It checks whether the locked version satisfies the version requirement in package.json.

Suppose:

package.json

"dependencies": {
  "some-package": "7.5.0"
}

And package-lock.json contains:

some-package → 6.0.0

Now you run:

npm install

What happens?

The lock file says:

6.0.0

but package.json says:

7.5.0

6.0.0 does not satisfy the requirement 7.5.0.

Therefore npm will resolve/install 7.5.0 and update the package-lock.json.

package.json
     │
     │ requires 7.5.0
     ▼
package-lock.json
     │
     │ currently has 6.0.0 ❌
     ▼
npm install
     │
     │ resolve dependency
     ▼
7.5.0
     │
     ▼
package-lock.json updated

Afterward, the lock file will contain the resolved 7.5.0 version.

Important distinction

If your package.json has:

"some-package": "^7.5.0"

then the situation is slightly different.

^7.5.0 means approximately:

7.x.x

So:

6.0.0  ❌
7.5.0  ✅
7.6.0  ✅
7.9.0  ✅
8.0.0  ❌

Therefore npm would need to update the lock file from the 6.x version to a compatible 7.x version.

And what about npm ci?

This is where the difference becomes important.

If:

package.json    → 7.5.0
package-lock    → 6.0.0

and you run:

npm ci

npm expects the lock file and package.json to be in sync. Because 6.0.0 doesn't satisfy 7.5.0, npm ci will fail rather than update the lock file.

So remember:

npm install
    ↓
Detect mismatch
    ↓
Resolve correct version
    ↓
Update package-lock.json
    ↓
Continue

Whereas:

npm ci
    ↓
Detect mismatch
    ↓
❌ Fail

Simple rule: npm install can repair/update the lock file; npm ci expects the lock file to already be correct.

← Back to Articles