Dependency Rules
Dependency rules keep install graphs small, auditable, and maintained so production services do not inherit abandoned or vulnerable packages.
Search across all documentation pages
Dependency rules keep install graphs small, auditable, and maintained so production services do not inherit abandoned or vulnerable packages.
Quick-reference recipe card - copy-paste ready.
{
"dependencies": {
"fastify": "^5.0.0"
},
"scripts": {
"audit": "npm audit --audit-level=high"
}
}npm ci
npm audit --audit-level=highWhen to reach for this:
# docs/dependencies.md (in repo)
## Add a dependency (RFC-lite)
1. Need stated in PR description
2. Weekly downloads > 100k OR org-approved exception
3. Last publish < 12 months ago
4. No install scripts OR reviewed in PR diff
5. License MIT/Apache-2.0/ISC only for prod deps# .github/workflows/audit.yml
on:
schedule:
- cron: "0 6 * * 1"
pull_request:
paths: [package.json, package-lock.json]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm audit --audit-level=high// Prefer Node built-ins when sufficient
import { createHash, randomUUID } from "node:crypto";
// instead of adding `uuid` + `crypto-js` for basic needsWhat this demonstrates:
node:crypto avoids extra dependency for UUID/hash.package.json ranges allow compatible updates; lockfile pins exact versions.npm audit reports known CVEs on locked graph.| Dep type | Range policy |
|---|---|
| Framework (express, fastify, nest) | Careful minor bumps, test suite |
Internal @acme/* | workspace or semver publish |
| Transitive | Controlled via lockfile only |
| devDependencies | Pin majors; update with toolchain |
@types/* devDeps track DefinitelyTyped; remove when package ships own types (Express 5).@types/node with Node 24.packages/utils.master branch - Unpinned mutable source. Fix: semver release from npm or git tag SHA.moment and date-fns and dayjs. Fix: org standard date library one pick.| Alternative | Use When | Don't Use When |
|---|---|---|
| Vendoring tiny MIT snippet | Single function, license clear | Large or GPL code |
| Private registry proxy | Cache and scan all tarballs | Solo hobby project |
| Zero-dep policy for libs | Published packages | Internal apps with normal deps |
Apps use ranges + lockfile. Libraries use ranges for consumers; avoid exact pins unless necessary.
Check last publish date, open issues, npm downloads; Socket flags unmaintained signals.
Generally avoid in proprietary services; legal review required for copyleft.
No fixed number; question each add. >50 direct deps warrants periodic knip and audit review.
Use sparingly to force transitive patch; document reason in PR; overrides confuse Renovate.
Fix before merge; Nest/ESLint plugins often need explicit peer installs.
Monorepo: yes single root lockfile. Polyrepo: independent audits per deployable.
SLA 24-48h for reachable RCE in HTTP stack; track in incident board.
Yes for developer machine risk; also run npm ci --omit=dev audit for prod graph.
ADR or ticket, migration branch, remove old dep same PR as new implementation.
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.
Reviewed by Chris St. John·Last updated Jul 19, 2026