# No bloated dependencies

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

## Why it matters

Every runtime dependency you ship is inherited by every consumer. `lodash` (full) adds ~72KB minified; `moment` adds ~230KB. A focused SDK with full `lodash` as a runtime dependency imposes that weight on every browser bundle that installs it — directly increasing page load times and Lighthouse performance scores for users who never touch the offending methods. ISO 25010 resource-utilization flags this; SLSA L1 supply chain concerns apply because each runtime dependency is an additional attack surface. CWE-1357 covers use of unnecessarily broad software components.

## Severity rationale

High because bloated runtime dependencies inflate every consumer's install size and bundle weight, and each transitive dependency expands the supply chain attack surface.

## Remediation

Audit runtime `dependencies` and replace heavy packages with built-in alternatives or lighter substitutes.

```json
// Before — heavy runtime deps:
{
  "dependencies": {
    "lodash": "^4.17.0",
    "axios": "^1.0.0",
    "moment": "^2.29.0"
  }
}

// After — zero runtime deps:
{
  "dependencies": {}
}
```

```ts
// Replace lodash.get with optional chaining:
// Before: _.get(obj, 'a.b.c', defaultVal)
// After:  obj?.a?.b?.c ?? defaultVal

// Replace axios with built-in fetch (Node 18+):
// Before: const { data } = await axios.get(url)
// After:  const data = await fetch(url).then(r => r.json())
```

Run `npx bundlephobia-cli <package-name>` before adding any new runtime dependency. Target: published package under 500KB gzipped.

## Detection

- **ID:** `bundle-size`
- **Severity:** `high`
- **What to look for:** Count all files included in the published package. examine `dependencies` in `package.json` for packages that are disproportionately large relative to their utility:
  1. `lodash` (full) instead of individual `lodash.*` packages or `lodash-es`
  2. `moment` instead of `date-fns` or `dayjs`
  3. `axios` when `fetch` (built-in) would suffice
  4. `aws-sdk` (v2, 70MB+) instead of `@aws-sdk/*` (v3 modular)
  5. Any dependency over 1MB for a task that could be a few lines of code
  6. Multiple dependencies that do the same thing (two HTTP clients, two date libraries)
  Also count total number of runtime `dependencies` — more than 10 is a yellow flag for a focused library.
- **Pass criteria:** Runtime dependencies are minimal and appropriately sized. No obviously bloated packages when lighter alternatives exist. Total dependency count is reasonable for the package's scope — published package must be under 500 KB gzipped for typical SDK usage. Report even on pass: "Published package size: X KB (Y files)."
- **Fail criteria:** One or more runtime dependencies are known to be disproportionately large (e.g., full `lodash` when only `get` is used), OR the package has more runtime dependencies than its scope justifies (e.g., 15 dependencies for a string utility library).
- **Skip (N/A) when:** The package has zero runtime dependencies. Also skip for Go (vendoring is different) and Rust (cargo handles dependency sizes differently).
- **Detail on fail:** `"5 runtime dependencies including lodash (full, 72KB minified) — only lodash.get is used. Replace with optional chaining (?.) or lodash-es for tree-shaking. Also includes axios when the built-in fetch API would suffice."`
- **Remediation:** Your consumers inherit your dependency tree. Every dependency you add increases their install size, build time, and supply chain risk.

  ```json
  // Before — heavy dependencies:
  {
    "dependencies": {
      "lodash": "^4.17.0",
      "axios": "^1.0.0",
      "moment": "^2.29.0"
    }
  }

  // After — minimal or none:
  {
    "dependencies": {}
  }
  ```

  ```ts
  // Replace lodash.get with optional chaining:
  // Before: _.get(obj, 'a.b.c', defaultVal)
  // After:  obj?.a?.b?.c ?? defaultVal

  // Replace axios with fetch:
  // Before: const { data } = await axios.get(url)
  // After:  const data = await fetch(url).then(r => r.json())
  ```

## External references

- iso-25010 performance-efficiency.resource-utilization
- ssdf PO.3.2
- slsa L1
- cwe CWE-1357

Taxons: supply-chain, code-quality

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