|$ curl https://forge-ai.dev/api/markdown?path=docs/npm/lockfiles
$cat docs/npm-—-lock-files-&-security.md
updated Recently·12 min read·published

npm — Lock Files & Security

npmIntermediate
Introduction

package-lock.json is the backbone of reproducible npm installs. It records the exact version of every dependency (and every dependency's dependency) that was resolved when npm install was last run. Without it, different machines could resolve different dependency trees.

This guide covers lock file internals, version differences, npm audit for vulnerability scanning, and security best practices for managing dependencies.

package-lock.json Structure

package-lock.json is an auto-generated file that you should commit to version control. It contains a complete dependency graph with resolved versions, integrity hashes, and dependency relationships.

package-lock.json
JSON
1// Simplified package-lock.json structure:
2{
3 "name": "my-app",
4 "lockfileVersion": 3,
5 "packages": {
6 "": {
7 "name": "my-app",
8 "dependencies": {
9 "express": "^4.21.0"
10 }
11 },
12 "node_modules/express": {
13 "version": "4.21.0",
14 "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
15 "integrity": "sha512-...sha512-base64-hash...",
16 "dependencies": {
17 "accepts": "~1.3.8",
18 "array-flatten": "1.1.1"
19 }
20 },
21 "node_modules/accepts": {
22 "version": "1.3.8",
23 "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
24 "integrity": "sha512-...sha512-hash..."
25 }
26 }
27}
28
29// Key fields:
30// lockfileVersion: Lock file format version (1, 2, or 3)
31// packages: Map of all installed packages with metadata
32// version: Resolved exact version
33// resolved: URL of the package tarball
34// integrity: Subresource Integrity hash (SRI)
35// dependencies: The package's own dependencies

info

Never manually edit package-lock.json. It is auto-generated and should only be modified by npm commands. If you need to change a dependency version, update package.json and run npm install.
Lock File Versions (v1 vs v2 vs v3)

npm has evolved the lock file format across major versions. Understanding the differences helps when working with different npm versions across projects.

Versionnpm VersionFormatKey Change
v1npm v5, v6Legacy (nested)Original lock file, nested structure
v2npm v7Flat (packages key)Flat structure with deterministic metadata
v3npm v8+Flat (packages key)Removed bundled field, smaller file
terminal
Bash
1# Check lock file version in your project:
2head -5 package-lock.json
3# {
4# "name": "my-app",
5# "lockfileVersion": 3,
6
7# npm v6 generates lockfileVersion: 1
8# npm v7 generates lockfileVersion: 2
9# npm v8+ generates lockfileVersion: 3
10
11# npm v7+ can read v1 lock files (migrates on update)
12# npm v6 cannot read v2/v3 lock files
13
14# Upgrade lock file version:
15rm package-lock.json && npm install
16# This generates the lock file for your current npm version
17
18# Downgrade lock file (if you need npm v6 compat):
19npm install --lockfile-version 1

warning

If your CI environment uses an older npm version than your local machine, the lock file format may cause issues. Ensure your CI npm version is at least npm v8 to support lockfile v3, or configure your local npm to use an older format with npm config set lockfile-version 2.
npm ci vs npm install

npm ci (clean install) is designed for reproducible environments. It uses the lock file exclusively and fails if it is out of sync with package.json.

terminal
Bash
1# npm install:
2# - Resolves dependency ranges
3# - Updates package-lock.json
4# - May install different versions than lock file
5# - Can add new dependencies
6# - Takes longer (resolution phase)
7
8# npm ci:
9# - Installs EXACTLY from package-lock.json
10# - Deletes node_modules first
11# - Fails if package.json and lock file mismatch
12# - Does NOT update lock file
13# - 2-10x faster than npm install
14# - Requires package-lock.json to exist
15
16# When npm ci fails:
17$ npm ci
18# npm ERR! cipm can only install packages
19# when your package.json and package-lock.json
20# are in sync. Please update your lock file.
21
22# Fix: run npm install locally and commit the lock file
23npm install
24git add package-lock.json
25git commit -m "chore: update lock file"
26git push
27
28# Then CI can run npm ci successfully

best practice

Always use npm ci in CI/CD pipelines. It is faster, deterministic, and catches the common mistake of forgetting to update the lock file after changing package.json.
npm audit — Vulnerability Scanning

npm audit scans your dependency tree against the npm Advisory database and reports known security vulnerabilities, along with their severity and remediation.

terminal
Bash
1# Run security audit
2npm audit
3
4# Output example:
5# === npm audit security report ===
6#
7# ┌───────────────┬──────────────────────────────────┐
8# │ Low │ Prototype Pollution │
9# ├───────────────┼──────────────────────────────────┤
10# │ Package │ lodash │
11# ├───────────────┼──────────────────────────────────┤
12# │ Dependency of │ express │
13# ├───────────────┼──────────────────────────────────┤
14# │ Path │ express > lodash │
15# ├───────────────┼──────────────────────────────────┤
16# │ More info │ https://npmjs.com/advisories/... │
17# └───────────────┴──────────────────────────────────┘
18#
19# found 1 low severity vulnerability
20# run npm audit fix to fix them, or npm audit for details
21
22# Show only high and critical vulnerabilities:
23npm audit --audit-level=high
24
25# JSON output for CI integration:
26npm audit --json
27
28# Audit only production dependencies:
29npm audit --production
30
31# Audit only devDependencies:
32npm audit --only=dev
33
34# If audit returns non-zero exit code:
35# 0 = no vulnerabilities
36# 1 = vulnerabilities found (or error)
37# Use in CI: npm audit --audit-level=high || true
npm audit fix

npm audit fix automatically installs compatible updates to resolve vulnerabilities. It respects SemVer ranges in your package.json.

terminal
Bash
1# Apply compatible security fixes
2npm audit fix
3# Only updates within existing range specifiers
4
5# Force fixes (may include breaking changes)
6npm audit fix --force
7# Updates to latest compatible version,
8# even if it means breaking changes
9
10# Install semver-major updates (breaking)
11npm audit fix --force --install-strategy=legacy
12
13# Dry run (see what would change)
14npm audit fix --dry-run
15
16# Only fix production dependencies
17npm audit fix --only=prod
18
19# Only fix devDependencies
20npm audit fix --only=dev
21
22# Example output:
23# npm audit fix
24# fixed 3 of 5 vulnerabilities in 14323 scanned packages
25# 2 vulnerabilities required semver-major updates
26# run npm audit fix --force to fix them

warning

Use npm audit fix --force with caution — it may upgrade packages to new major versions that include breaking changes. Always review the changes in package-lock.json after a force fix and run your test suite.
npm fund

npm fund displays funding information for your dependencies, showing how you can support the open-source projects your application depends on.

terminal
Bash
1# Show funding info for all dependencies
2npm fund
3
4# Output example:
5# my-app@1.0.0
6# ├── dependencies:
7# │ ├── express
8# │ │ └── https://opencollective.com/express
9# │ ├── lodash
10# │ │ └── https://github.com/sponsors/jdalton
11# │ └── chalk
12# │ └── https://github.com/chalk/chalk?sponsor=1
13# └── devDependencies:
14# └── typescript
15# └── https://github.com/sponsors/microsoft
16
17# Show funding for a specific package:
18npm fund express
19
20# Open the funding URL in browser:
21npm fund --open express
22
23# Include funding in your package.json:
24{
25 "funding": {
26 "type": "individual",
27 "url": "https://github.com/sponsors/your-name"
28 }
29}
30// Or as a string:
31{ "funding": "https://github.com/sponsors/your-name" }
SRI (Subresource Integrity) in Lockfiles

Each entry in package-lock.json includes an integrity field containing a Subresource Integrity (SRI) hash. This ensures the downloaded package matches what was originally resolved, preventing tampering or corruption.

package-lock.json
JSON
1// SRI integrity field in package-lock.json:
2"node_modules/express": {
3 "version": "4.21.0",
4 "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
5 "integrity": "sha512-qiIH1n0H3qRlF3TjehDdR2D7N6+0Zx1NMB2L1h/3rT6rDkKkHN8y2z5kf2UcjVqoA4H6hCL52OOpAVhvVq1w=="
6}
7
8// The integrity field format:
9// sha512-<base64-hash>
10
11// How npm uses SRI:
12// 1. npm resolves the tarball URL
13// 2. Downloads the tarball
14// 3. Computes the SHA-512 hash
15// 4. Compares with integrity field
16// 5. If mismatch → installation fails
17
18// This protects against:
19// - Registry compromise (modified tarball)
20// - Man-in-the-middle attacks
21// - Corrupted downloads
22// - npm registry CDN issues
23
24// SRI is the reason npm install is considered secure

info

Never modify the integrity field manually. If you get integrity check errors, it likely means the package was modified on the registry, or you have a network issue (proxy, MITM). Run npm cache verify first, then npm install to regenerate the lock file.
Security Best Practices for Dependencies

Commit Lock Files

Always commit package-lock.json. It ensures reproducible builds across environments and protects against unexpected dependency updates. This is the single most important npm security practice.

Run npm audit Regularly

Run npm audit in CI and locally. Consider using GitHub Dependabot or Renovate to automatically create PRs for vulnerable dependencies.

Use npm ci in CI/CD

npm ci installs exactly from the lock file, ensuring CI never installs unexpected versions. It also catches lock file drift between environments.

Pin Versions for Production

Consider using --save-exact for production dependencies. Combined with the lock file, this provides maximum control over what runs in production.

Review Dependency Changes

Review package-lock.json changes during code reviews. Unexpected additions or removals of dependencies can indicate malicious packages or unintended side effects.

Best Practices

Always Commit package-lock.json

The lock file is essential for reproducible builds. Without it, every npm installcould resolve different versions, leading to "works on my machine" bugs.

Audit Dependencies Before Adding

Before adding a new dependency, check its download count, maintenance status, and security advisories. A package with 100 weekly downloads and no recent updates is a security risk.

Use npm Audit in CI

Add npm audit --audit-level=high to your CI pipeline. This prevents merging code with known high or critical vulnerabilities.

Keep npm Updated

Run npm install -g npm@latest periodically. Newer npm versions include security fixes, faster installs, and better lock file formats.

$Blueprint — Engineering Documentation·Section ID: NPM-LOCK·Revision: 1.0