What Is a Lock File?
A lock file is an automatically generated file that records the exact version of every dependency — including transitive dependencies — installed in your project at a given point in time. When you run your install command, the package manager reads the lock file and installs precisely those versions, ensuring every developer on your team and every CI environment gets an identical node_modules tree.
Without a lock file, two developers running npm install a week apart could end up with subtly different dependency trees, leading to the classic "works on my machine" problem.
The Three Major Lock Files
package-lock.json (npm)
Introduced in npm v5, package-lock.json locks the entire dependency tree including all nested dependencies. It uses a flat structure that records each package's resolved URL, integrity hash, and exact version. npm v7+ changed the format significantly to support workspaces and to include node_modules metadata directly in the file.
- Location: Project root
- Generated by:
npm install - Reproduced with:
npm ci(preferred for CI)
yarn.lock (Yarn Classic & Berry)
Yarn's lock file uses a custom human-readable format (Yarn Classic) or a YAML-like format (Yarn Berry / v2+). It is deterministic by design and was one of the first lock files to gain widespread adoption in the JavaScript ecosystem. Yarn Berry introduced Plug'n'Play, which removes node_modules entirely, making the lock file even more critical.
- Location: Project root
- Generated by:
yarn install - Reproduced with:
yarn install --frozen-lockfile
pnpm-lock.yaml (pnpm)
pnpm uses a YAML-based lock file and pairs it with a content-addressable store that hard-links packages across projects. This makes installs significantly faster and disk-efficient. The lock file format is more verbose but captures dependency relationships more explicitly.
- Location: Project root
- Generated by:
pnpm install - Reproduced with:
pnpm install --frozen-lockfile
Comparison at a Glance
| Feature | npm | Yarn | pnpm |
|---|---|---|---|
| Lock file name | package-lock.json | yarn.lock | pnpm-lock.yaml |
| Format | JSON | Custom / YAML | YAML |
| Human readable | Moderate | Good | Good |
| Workspace support | v7+ | Yes | Yes |
| CI freeze command | npm ci | --frozen-lockfile | --frozen-lockfile |
Should You Commit Your Lock File?
For applications: always commit the lock file. It guarantees reproducibility across developer machines, CI runners, and production builds.
For libraries: this is more nuanced. Library consumers install the library into their own dependency tree, so your lock file doesn't affect them. Many maintainers choose not to commit lock files for libraries to avoid confusion, but committing it still benefits your own test suite.
Best Practices
- Never manually edit a lock file — always let the package manager regenerate it.
- Use the freeze/ci flag in automated pipelines to prevent accidental updates.
- Review lock file diffs in pull requests to catch unexpected dependency upgrades.
- Use tools like
npm auditorpnpm auditto check for known vulnerabilities in locked versions.
Choosing the right package manager often comes down to team preference and monorepo requirements, but regardless of your choice, treating the lock file as a first-class citizen in your repository is a non-negotiable best practice.