# Minimal runtime dependencies

- **Pattern:** `ab-002381` (`sdk-package-quality.build-distribution.minimal-deps`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002381
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002381)

## 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.

```json
// 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 `dependencies` in `package.json` (not `devDependencies`). For each dependency, assess whether it's:
  1. **Essential** — provides core functionality the package couldn't reasonably implement (e.g., a crypto library, a database driver)
  2. **Convenience** — saves a few lines of code but could be replaced with built-in APIs (e.g., `node-fetch` on Node.js 18+, `uuid` when `crypto.randomUUID()` exists)
  3. **Unused** — listed but never imported in source code
  Check for dependencies that are only used in tests or development but mistakenly placed in `dependencies` instead of `devDependencies`.
- **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.

  ```json
  // 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 `fetch` on Node.js 18+ instead of `node-fetch`. Use `crypto.randomUUID()` instead of the `uuid` package. Check `npx depcheck` to find unused dependencies.

---

## External references

- iso-25010 maintainability.modifiability
- ssdf PO.3.2
- slsa L1
- cwe CWE-1357

Taxons: supply-chain, code-quality

HTML version: https://auditbuffet.com/patterns/ab-002381
