Package Managers Best Practices
Rules that keep installs reproducible, audits meaningful, and monorepos maintainable.
How to Use This List
- Apply on new repos before the first production deploy.
- Revisit when adding workspaces or switching npm/pnpm/Yarn.
- Enforce via CI (
npm ci, audit gates) rather than README reminders. - Check items during dependency upgrade PRs and platform Node bumps.
A - Manager & Lockfile Policy
- One package manager per repository. Mixed lockfiles guarantee divergent
node_modulesgraphs. - Commit the lockfile for every application and deployable service. Reproducible CI and Docker builds depend on it.
- Use
npm ciin CI, notnpm install. Prevents silent resolution drift on every pipeline run. - Document the chosen manager in README. Include install, bootstrap, and troubleshooting commands.
- Pin Node in CI and Docker to match
engines. e.g.24.18.0, not floating24.xonly.
B - Dependencies & Scripts
- Separate
dependenciesanddevDependenciescorrectly. TypeScript, ESLint, and test runners are dev-only. - Keep
scriptsas the automation contract.npm test,npm run build, andnpm run typecheckwork locally and in CI. - Avoid heavy
postinstallscripts. Slow installs hurt every developer and every cached CI job. - Use
prepublishOnlyfor publish gates. Tests and typecheck run before tarballs reach the registry. - Prefer lockfile-pinned CLIs over bare
npxin scripts.tsxandeslintbelong indevDependencies.
C - Workspaces & Monorepos
- Use
workspace:*for internal packages. Symlink local libs instead of manualfile:paths. - Build shared packages before dependents. Order tasks in root scripts or use Turborepo dependsOn.
- Export through package
exports, not deep relative imports. Cross-package../../packages/foo/srcbreaks boundaries. - One root lockfile for the whole monorepo. Per-package lockfiles defeat workspace linking benefits.
- Name workspaces with consistent scope.
@acme/api,@acme/sharedclarifies ownership.
D - Security & Compliance
- Run
npm audit --audit-level=highon every dependency PR. Block merge until fixed or excepted with expiry. - Review install-script changes in dependency diffs.
postinstalladditions are high risk. - Enable provenance for published internal libraries. Consumers verify CI-built artifacts.
- Set
engine-strict=truein.npmrc. Unsupported Node fails at install, not in production. - Automate dependency updates with grouped Renovate/Dependabot PRs. Smaller, testable upgrade batches.
E - Publishing & Versioning
- Use strict
fileswhitelist when publishing. Never ship tests,.env.examplesecrets, or rawsrc/unintentionally. - Follow semver for published packages. Breaking API changes require major bumps.
- Ship compiled JS and
.d.tsfor TypeScript libraries. Consumers should not compile your source. - Tag releases in git when publishing.
npm versionplus CI publish keeps registry and source aligned. - Deprecate bad versions instead of unpublishing.
npm deprecatewarns consumers without breaking lockfiles.
FAQs
Why is one lockfile policy so important?
Two lockfiles mean two graphs. CI may install with npm while a developer uses Yarn, masking bugs until production.
When is pnpm better than npm for backends?
Large monorepos with many duplicate transitives benefit from pnpm disk efficiency and stricter dependency boundaries.
Should we commit node_modules?
No. Commit lockfiles only. CI and Docker rebuild node_modules from the lockfile.
How do we handle emergency patches?
Open a PR updating the lockfile, run full CI, deploy. Avoid npm install directly on production servers.
What goes in root package.json in a monorepo?
workspaces, shared dev tooling, orchestration scripts (build, test, lint). Deployables keep their own runtime deps.
Should libraries pin exact dependency versions?
Libraries use ranges in package.json; the app lockfile pins exact versions for the deployable graph.
How do we onboard new developers?
Document Node version (Volta/nvm), npm ci, and npm run dev. engine-strict catches mismatches immediately.
Is npm audit enough for supply chain?
Necessary but not sufficient. Layer Socket or similar for behavior analysis and typosquat detection.
When should we switch package managers?
When monorepo install time or phantom dependency bugs hurt velocity. Plan a one-PR migration with lockfile regeneration and full CI.
How do we version internal workspace packages?
0.0.0 is fine for private-only packages. Bump semver before publishing externally or when consumers outside the repo appear.
Related
- Package Managers Basics - npm, pnpm, Yarn selection
- Lockfiles & Reproducible Installs -
npm cidetails - Supply Chain: npm audit & Socket - merge gates
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.