Pin exact versions for all dependencies in production (no ^, ~, or * ranges). Unpinned dependencies silently pull in new versions that can introduce breaking changes, security vulnerabilities, or performance regressions — and you won't know until production breaks.
Unpinned dependencies mean your production build is non-deterministic — the same code can produce different builds depending on when npm install runs. A patch release with a breaking change or a compromised package version gets pulled in silently. You discover the problem in production, not in CI, because the versions differ between environments.
BeforeMerge scans your pull requests against this rule and 4+ others. Get actionable feedback before code ships.
When you specify "react": "^18.2.0", npm will install any version matching >=18.2.0 <19.0.0. This means your production build depends on when npm install runs — not on what you tested. A new patch release published between your last CI run and your production deploy will be silently included.
This has caused real-world incidents: the colors and faker packages were intentionally sabotaged by their maintainer, breaking thousands of production applications that had unpinned versions. The event-stream attack injected cryptocurrency-stealing code through a patch update that was automatically pulled into applications with ^ ranges.
Pinning exact versions ensures that your CI build, staging environment, and production deployment all use identical dependencies. Lockfiles help but are not sufficient — they can be regenerated, and not all tools respect them.
Pin exact versions for all production dependencies (dependencies in package.json). Use exact version strings (e.g., "18.2.0") without ^, ~, or * prefixes. Use a lockfile (package-lock.json or pnpm-lock.yaml) and commit it to version control.
{
"dependencies": {
"react": "^18.2.0",
"next": "~14.1.0",
"lodash": "*",
"axios": ">=1.0.0"
}
}{
"dependencies": {
"react": "18.2.0",
"next": "14.1.4",
"lodash": "4.17.21",
"axios": "1.6.7"
}
}Search for version ranges in package.json:
grep -E '\^|~|\*|>=' package.jsonUse npm ls or pnpm ls to check which versions are actually installed versus what is specified.
npm ls --depth=0 to see currently installed versions^ and ~ prefixes with the exact installed versionpackage-lock.json or pnpm-lock.yaml)npm config set save-exact truenpm ci (not npm install) in CI/CD to install from lockfile only