Dependency Management
Every dependency is code you didn't write, can't fully review, and must maintain forever. Choose carefully.
Evaluating New Dependencies
Before adding a dependency, ask:
- Can I implement this in under 100 lines without the library? If yes, consider doing so.
- Is the library actively maintained? (Last release date, open issue count, PR response time)
- How many transitive dependencies does it add? (
npm why, cargo tree, pip show)
- Is the license compatible with this project?
- Has it had security advisories in the past 12 months, and how were they handled?
Prefer dependencies that do one thing well over ones that solve everything.
Lock Files
- Commit lock files (
package-lock.json, Cargo.lock, poetry.lock, go.sum) for applications. Lock files guarantee reproducible builds.
- For libraries, commit
Cargo.lock (Rust) but do not commit package-lock.json (npm) — downstream consumers resolve their own trees.
- Never edit lock files by hand. Regenerate them by upgrading the source manifest and re-running the package manager.
- Treat lock file diffs in PRs as code — review them. Unexpected transitive version changes are a supply chain risk.
Keeping Dependencies Updated
- Use Dependabot, Renovate, or a similar bot to open automatic upgrade PRs. Configure it with a schedule (weekly for minor/patch, manual for major) and a reviewer assignment.
- Group patch updates into a single PR; review minor and major updates individually.
- Read changelogs for every minor and major upgrade before merging. Don't auto-merge without a changelog review.
- Prefer upgrading one dependency at a time so regressions are attributable.
Security Auditing
- Run dependency audits in CI on every merge:
npm audit, cargo audit, pip-audit, govulncheck.
- Set audit to fail CI on
high or critical severities. moderate should be tracked and addressed within a sprint.
- Subscribe to security advisories for your major dependencies via GitHub Advisory Database or the relevant language ecosystem's advisory feed.
- Audit licenses in CI with
license-checker (npm) or cargo-deny (Rust). An undiscovered GPL transitive dependency can create legal obligations.
Pinning and Reproducibility
- Pin exact versions in production application manifests:
"react": "18.2.0" not "react": "^18". Floating ranges shift the build on every install.
- For Docker base images, pin to a digest (
node@sha256:...) not just a tag. Tags are mutable.
- For Go,
go mod tidy removes unused dependencies — run it before every release.
- For Python, use
pip-compile (pip-tools) or poetry lock to generate a pinned requirements file from a high-level spec.
Reducing the Footprint
- Periodically audit for unused dependencies:
npm-check, cargo machete, deptry (Python). Remove anything not actively used.
- Prefer
devDependencies over dependencies for build and test tools — they don't ship to production.
- When a dependency is used in only one place, evaluate whether the function can be inlined and the dep removed.
Checklist
1---2name: dependency-management3description: Keep dependencies secure, minimal, and up to date. Use when auditing a project's supply chain, adding new libraries, evaluating upgrades, or hardening a CI pipeline against dependency risks.4license: Apache-2.05---67# Dependency Management89Every dependency is code you didn't write, can't fully review, and must maintain forever. Choose carefully.1011## Evaluating New Dependencies1213Before adding a dependency, ask:14- Can I implement this in under 100 lines without the library? If yes, consider doing so.15- Is the library actively maintained? (Last release date, open issue count, PR response time)16- How many transitive dependencies does it add? (`npm why`, `cargo tree`, `pip show`)17- Is the license compatible with this project?18- Has it had security advisories in the past 12 months, and how were they handled?1920Prefer dependencies that do one thing well over ones that solve everything.2122## Lock Files2324- Commit lock files (`package-lock.json`, `Cargo.lock`, `poetry.lock`, `go.sum`) for applications. Lock files guarantee reproducible builds.25- For libraries, commit `Cargo.lock` (Rust) but do not commit `package-lock.json` (npm) — downstream consumers resolve their own trees.26- Never edit lock files by hand. Regenerate them by upgrading the source manifest and re-running the package manager.27- Treat lock file diffs in PRs as code — review them. Unexpected transitive version changes are a supply chain risk.2829## Keeping Dependencies Updated3031- Use Dependabot, Renovate, or a similar bot to open automatic upgrade PRs. Configure it with a schedule (weekly for minor/patch, manual for major) and a reviewer assignment.32- Group patch updates into a single PR; review minor and major updates individually.33- Read changelogs for every minor and major upgrade before merging. Don't auto-merge without a changelog review.34- Prefer upgrading one dependency at a time so regressions are attributable.3536## Security Auditing3738- Run dependency audits in CI on every merge: `npm audit`, `cargo audit`, `pip-audit`, `govulncheck`.39- Set audit to fail CI on `high` or `critical` severities. `moderate` should be tracked and addressed within a sprint.40- Subscribe to security advisories for your major dependencies via GitHub Advisory Database or the relevant language ecosystem's advisory feed.41- Audit licenses in CI with `license-checker` (npm) or `cargo-deny` (Rust). An undiscovered GPL transitive dependency can create legal obligations.4243## Pinning and Reproducibility4445- Pin exact versions in production application manifests: `"react": "18.2.0"` not `"react": "^18"`. Floating ranges shift the build on every install.46- For Docker base images, pin to a digest (`node@sha256:...`) not just a tag. Tags are mutable.47- For Go, `go mod tidy` removes unused dependencies — run it before every release.48- For Python, use `pip-compile` (pip-tools) or `poetry lock` to generate a pinned requirements file from a high-level spec.4950## Reducing the Footprint5152- Periodically audit for unused dependencies: `npm-check`, `cargo machete`, `deptry` (Python). Remove anything not actively used.53- Prefer `devDependencies` over `dependencies` for build and test tools — they don't ship to production.54- When a dependency is used in only one place, evaluate whether the function can be inlined and the dep removed.5556## Checklist5758- [ ] New dependencies evaluated for maintenance health, license, and transitive footprint.59- [ ] Lock file committed and reviewed in PRs.60- [ ] Dependency audit running in CI, failing on high/critical CVEs.61- [ ] Automated upgrade bot configured with changelog review requirement.62- [ ] License audit in CI for production application.63- [ ] Unused dependencies pruned on a quarterly schedule.