Minimal runtime dependencies
Why it matters
Every dependency in dependencies is installed by every consumer, even in production. TypeScript, @types/*, test runners, and build tools in dependencies instead of devDependencies inflate the install footprint of every project that depends on yours. node-fetch as a runtime dependency in a package that declares engines: { node: '>=18' } installs a redundant polyfill of a built-in. CWE-1357 covers use of unnecessarily broad components; SLSA L1 and SSDF PO.3.2 both require that the published artifact's dependency tree is intentional and minimal.
Severity rationale
Medium because misplaced or unnecessary runtime dependencies increase install size and supply chain surface area for all consumers, without providing any functional benefit.
Remediation
Audit dependencies and move build tools, type packages, and test frameworks to devDependencies. Replace convenience packages with built-in equivalents.
// Before — misplaced deps:
{
"dependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"node-fetch": "^3.0.0",
"vitest": "^1.0.0"
}
}
// After — clean runtime deps:
{
"dependencies": {},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"vitest": "^1.0.0"
}
}
Run npx depcheck to surface unused dependencies. Replace node-fetch with built-in fetch (Node 18+) and uuid with crypto.randomUUID(). Target: no more than 10 runtime dependencies for a typical SDK.
Detection
-
ID:
minimal-deps -
Severity:
medium -
What to look for: Count all runtime dependencies. For each dependency, count the runtime
dependenciesinpackage.json(notdevDependencies). For each dependency, assess whether it's:- Essential — provides core functionality the package couldn't reasonably implement (e.g., a crypto library, a database driver)
- Convenience — saves a few lines of code but could be replaced with built-in APIs (e.g.,
node-fetchon Node.js 18+,uuidwhencrypto.randomUUID()exists) - Unused — listed but never imported in source code
Check for dependencies that are only used in tests or development but mistakenly placed in
dependenciesinstead ofdevDependencies.
-
Pass criteria: Every runtime dependency serves an essential purpose. No obviously misplaced devDependencies, no unused dependencies, no convenience packages that duplicate built-in functionality — no more than 10 runtime dependencies for a typical SDK to minimize consumer bundle impact. Report: "X runtime dependencies found."
-
Fail criteria: One or more runtime dependencies are clearly misplaced (test frameworks, build tools, or linters in
dependencies), unused (never imported), or unnecessary (duplicating built-in Node.js functionality available in the package's minimum supported Node.js version). -
Skip (N/A) when: The package has zero runtime dependencies. Also skip for Go and Rust where dependency management conventions differ significantly.
-
Detail on fail:
"typescript and @types/node are in dependencies instead of devDependencies. vitest is in dependencies — should be devDependencies. node-fetch is in dependencies but package.json engines requires Node.js >= 18 which has built-in fetch." -
Remediation: Every runtime dependency is a liability — it increases install size, expands the supply chain attack surface, and may conflict with consumer versions.
// Before — misplaced and unnecessary deps: { "dependencies": { "typescript": "^5.0.0", "@types/node": "^20.0.0", "node-fetch": "^3.0.0", "vitest": "^1.0.0" } } // After — only what consumers need at runtime: { "dependencies": {}, "devDependencies": { "typescript": "^5.0.0", "@types/node": "^20.0.0", "vitest": "^1.0.0" } }Use the built-in
fetchon Node.js 18+ instead ofnode-fetch. Usecrypto.randomUUID()instead of theuuidpackage. Checknpx depcheckto find unused dependencies.
External references
- iso-25010:2011 · maintainability.modifiability — Modifiability — minimal runtime deps reduce version-conflict surface
- ssdf:800-218 · PO.3.2 — Review and update software dependency requirements
- slsa:1.0 · L1 — SLSA L1 — fewer deps shrink provenance scope
- cwe · CWE-1357 — Reliance on Insufficiently Trustworthy Component
Taxons
History
- 2026-04-18·v1.0.0·Initial import from sdk-package-quality·automated