Dependency Pinning
Dependency pinning fixes exact versions and integrity hashes for every dependency, so installs are reproducible and an upstream release cannot silently change your build.
Definition
Dependency pinning records exact versions, and ideally integrity hashes, for direct and transitive dependencies in a lockfile, so that every install resolves to the same artifact regardless of when or where it runs.
Context and scope
It is essential for production services, CI pipelines, and anything subject to supply chain review, where an unexpected minor release can break a build or introduce a compromised package.
Common misconceptions
- Pinning means never upgrading — pinned versions still need scheduled, tested upgrades.
- A caret range is a pin — ^1.4.2 allows any 1.x release, including ones published tomorrow.
- The lockfile alone secures the build — installs that ignore the lockfile or fetch from untrusted registries bypass it.
Anti-patterns
- Committing package.json but ignoring the lockfile in version control
- Using latest tags in Dockerfiles or CI images
- Pinning direct dependencies while leaving transitive ones floating
Related concepts
Authoritative source
https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json
Exact versions and hashes
Pinning starts with a lockfile that records the resolved version of every package, direct and transitive, plus a hash of the downloaded artifact. CI then installs with a frozen-lockfile mode so the resolver cannot quietly choose a newer release. Container base images should be pinned by digest rather than a mutable tag, and CI actions by commit SHA rather than a version branch.
pnpm install --frozen-lockfile
docker pull node:22.11.0-bookworm-slim@sha256:0123456789abcdef
When to use it
Pin dependencies for anything that ships to users or runs in production. The practice matters most when builds must be reproducible months later, when auditors ask what code is running, or when the ecosystem has suffered a typosquatting or maintainer-compromise incident. Prototypes can float, but the moment a project has a deployment, it needs a lockfile.
Trade-offs
Pinning trades freshness for determinism. Security patches no longer arrive automatically, so teams need automated update pull requests and a testing path that makes merging them cheap. A scheduled upgrade cadence keeps a pin from becoming a fossil. Over-pinning transitive dependencies by hand creates conflicts; let the package manager resolve and commit the lockfile instead.
Example and misconceptions
A service pins every image by digest. When an upstream maintainer account is compromised and a malicious patch is published, the next build still installs the recorded artifact, and the update bot surfaces the change for review. The misconception that a lockfile alone is enough ignores install flags and registry trust. Related concepts: semantic versioning, supply chain security, and build cache.