Skip to content

ADR-0006: pnpm for Package Management

Status: Accepted Date: 2024-12-01 (Estimated) Deciders: GetCimple Team Tags: tooling, developer-experience, monorepo

Context

GetCimple is structured as a monorepo with multiple packages (apps, shared libraries, docs). We need a package manager that handles:

Requirements: - Monorepo workspace support - Fast installation and dependency resolution - Disk space efficiency (multiple projects, node_modules can be huge) - Lock file for reproducible builds - Compatible with GitHub Actions CI/CD

Constraints: - 3-person team (simple tooling preferred) - Monorepo structure: apps/, packages/, docs/ - Must work with Vite, React, MkDocs build processes - No additional cost

Options Considered

Option A: pnpm

Description: Fast, disk space-efficient package manager with native monorepo support.

Pros: - βœ… Disk efficiency: Uses content-addressable storage (saves GB with multiple projects) - βœ… Fast: Faster than npm and yarn (especially fresh installs) - βœ… Monorepo native: Workspace support built-in (pnpm-workspace.yaml) - βœ… Strict dependencies: Prevents phantom dependencies (only declared deps accessible) - βœ… Lock file: pnpm-lock.yaml ensures reproducible builds - βœ… Compatible: Works with all npm packages - βœ… Growing adoption: Used by Vue, Vite, and other major projects

Cons: - ❌ Less common than npm (some developers unfamiliar) - ❌ Slightly different CLI from npm (pnpm add vs npm install) - ❌ Some edge case compatibility issues with older packages

Estimated Effort: 1 hour to switch from npm


Option B: npm (default)

Description: Node.js default package manager.

Pros: - βœ… Everyone knows it - βœ… No installation required - βœ… Works everywhere - βœ… Workspaces support (npm 7+)

Cons: - ❌ Slow: Slowest of the three options - ❌ Disk space: Duplicates node_modules across workspace packages - ❌ Phantom deps: Allows importing undeclared dependencies (risky) - ❌ Large lock file

Estimated Effort: Already using (no switch needed)


Option C: Yarn (v3/v4 Berry)

Description: Alternative package manager with Plug'n'Play mode.

Pros: - βœ… Fast (comparable to pnpm) - βœ… Yarn workspaces mature - βœ… Plug'n'Play mode (no node_modules)

Cons: - ❌ Plug'n'Play compatibility issues with some tools - ❌ More complex than pnpm - ❌ Larger lock file than pnpm - ❌ Zero-installs feature controversial

Estimated Effort: 2-3 hours to configure Plug'n'Play properly


Decision

We chose: Option A - pnpm

Rationale: 1. Monorepo optimized: Native workspace support, perfect for our apps/ and packages/ structure 2. Disk space: Content-addressable storage saves gigabytes (important with MkDocs, React, multiple apps) 3. Speed: 2-3x faster than npm for fresh installs (CI/CD runs faster) 4. Strict dependencies: Prevents phantom dependency bugs (quality improvement) 5. Future-proof: Growing adoption, momentum in ecosystem 6. Simple migration: Compatible with npm, easy to switch

Key Trade-offs Accepted: - We're accepting slightly less familiarity (pnpm vs npm) for performance and disk savings - We're accepting potential edge case issues (very rare) for strictness benefits

Consequences

Positive

  • βœ… Faster CI/CD: GitHub Actions runs 30-50% faster (fewer npm install minutes)
  • βœ… Disk savings: ~2-3GB saved vs npm across all projects and node_modules
  • βœ… Monorepo clarity: pnpm-workspace.yaml makes package relationships explicit
  • βœ… Dependency hygiene: Phantom dependency bugs prevented (builds fail if deps not declared)
  • βœ… Reproducible builds: pnpm-lock.yaml ensures consistent dependency versions

Negative

  • ⚠️ Onboarding: New team members may need 5-minute pnpm intro
  • ⚠️ CLI differences: Must use pnpm add not npm install (easy to learn)
  • ⚠️ Edge cases: Very rare package incompatibilities (can use shamefully-hoist as escape hatch)

Risks

Risk Likelihood Impact Mitigation
Package incompatibility LOW LOW Use .npmrc shamefully-hoist option; fall back to npm for specific packages
Team forgets pnpm commands LOW LOW Add package.json scripts (pnpm dev β†’ npm run dev works); document in README
pnpm abandoned by maintainers LOW MEDIUM Growing adoption reduces risk; can migrate back to npm if needed (low effort)

Compliance Note

ACSC Essential 8 Impact: - Relevant Control: Application Control (Maturity Level 1-2) - Dependency integrity: pnpm's strict mode prevents undeclared dependencies - Supply chain security: Content-addressable storage provides integrity verification

Australian Data Residency: - Not applicable: Package manager is local tooling

Audit Trail: - pnpm-lock.yaml tracked in Git provides full dependency audit trail - Reproducible builds support compliance verification

Implementation Notes

Prerequisites: - Node.js 18+ installed - pnpm installed globally (npm install -g pnpm@latest)

Integration Points: - GitHub Actions: Use pnpm/action-setup@v2 for CI/CD - Vite: Works seamlessly with pnpm - Monorepo: pnpm-workspace.yaml defines workspace packages

Configuration:

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'

Monitoring: - CI/CD build times (expect 30-50% faster vs npm) - Disk usage savings (track node_modules size)

Documentation Updates Needed: - βœ… README.md updated with pnpm commands - βœ… Development guide uses pnpm - βœ… GitHub Actions workflows use pnpm

Revisit

Revisit By: N/A (low-risk decision, no planned revisit) Blast Radius: LOW - Easy to switch back to npm if needed (1-2 hours)

Conditions for Revisit: - Widespread compatibility issues (>5 packages requiring workarounds) - pnpm project loses momentum (maintainer departure, no updates) - npm releases features that eliminate pnpm advantages

Next Review: N/A (only revisit if problems arise)


References


Version History

Version Date Author Changes
1.0 2025-10-20 Claude Initial ADR capturing historical decision