# ADR-0002: Package Manager Unification with pnpm

**Status**: Accepted **Date**: 2026-01-10 **Authors**: Development Team
**Reviewers**: Architecture Team **Supersedes**: N/A **Superseded by**: N/A

## Context and Problem Statement

The Oshun monorepo consolidation requires a unified package manager strategy.
Currently, the two primary codebases use different package managers:

**Lilith (Current State)**:

- Uses Yarn workspaces (yarn.lock present)
- Also has package-lock.json (npm artifacts)
- Workspace configuration via `workspaces` array in package.json
- No pnpm configuration

**Yemaya (Current State)**:

- Uses pnpm 10.25.0 (specified via `packageManager` field)
- Has mature pnpm-workspace.yaml with dependency catalog
- Well-configured .npmrc with hoisting rules
- Uses Turbo for build orchestration (being replaced by Nx)

We need to select a single package manager for the unified Oshun monorepo that:

- Supports efficient monorepo workflows at scale
- Integrates well with Nx workspace tooling
- Provides consistent dependency resolution across all packages
- Minimizes disk space usage and install times
- Offers strong security and dependency isolation

## Decision Drivers

- **Monorepo Optimization**: Native workspace support with efficient linking and
  dependency hoisting
- **Disk Efficiency**: Storage optimization for large repositories with many
  packages
- **Install Performance**: Fast dependency resolution and installation
- **Dependency Strictness**: Prevention of phantom dependencies and undeclared
  imports
- **Nx Integration**: Seamless integration with Nx workspace features
- **Developer Experience**: Familiar commands, good error messages, IDE support
- **Existing Investment**: Leverage existing pnpm configuration from Yemaya
- **Lock File Stability**: Deterministic builds with minimal lockfile churn
- **Security**: Supply chain security features and audit capabilities

## Considered Options

### Option 1: pnpm (Recommended)

**Description**: Performant npm - a fast, disk space efficient package manager
with strict dependency isolation and native workspace support.

**Pros**:

- ✅ **Disk Efficiency**: Content-addressable storage shares packages globally;
  ~60-70% disk savings vs npm
- ✅ **Strict by Default**: Prevents phantom dependencies - packages can only
  import declared dependencies
- ✅ **Native Workspaces**: First-class monorepo support with
  `pnpm-workspace.yaml`
- ✅ **Dependency Catalog**: Centralized version management via `catalog:`
  prefix
- ✅ **Fast Installs**: Typically 2-3x faster than npm for cold installs
- ✅ **Existing Configuration**: Yemaya already has mature pnpm setup to build
  upon
- ✅ **Excellent Nx Integration**: Nx has first-class pnpm support
- ✅ **Symlink Strategy**: Proper node_modules structure with symlinks for
  correct resolution
- ✅ **Lockfile Stability**: Minimal lockfile changes when adding/removing
  packages
- ✅ **Active Development**: Rapid feature development, responsive maintainers

**Cons**:

- ❌ **Learning Curve**: Developers unfamiliar with pnpm need onboarding
- ❌ **Compatibility Issues**: Some packages with hardcoded node_modules
  assumptions may break
- ❌ **Migration Effort**: Lilith packages need conversion from Yarn workspaces
- ❌ **Symlink Complexity**: Debugging can be harder due to symlinked structure

**Cost**: Low - pnpm is free, migration is straightforward **Risk**: Low -
mature, widely adopted, well-documented **Effort**: 2-3 days for full migration
and verification

### Option 2: Yarn (Classic or Berry)

**Description**: Facebook's package manager with workspaces support. Yarn Berry
(v3+) introduces Plug'n'Play (PnP) for zero-install workflows.

**Pros**:

- ✅ **Lilith Familiarity**: Lilith already uses Yarn workspaces
- ✅ **Zero-Install (Berry)**: Commit dependencies to repo for instant installs
- ✅ **Stable and Mature**: Long track record, large community
- ✅ **Good Workspace Support**: Native workspaces with selective versioning

**Cons**:

- ❌ **Disk Inefficiency (Classic)**: Each project has full node_modules copy
- ❌ **PnP Compatibility Issues (Berry)**: Many packages incompatible with
  Plug'n'Play
- ❌ **No Dependency Catalog**: Manual version synchronization across packages
- ❌ **Slower than pnpm**: Install times 30-50% slower for large monorepos
- ❌ **Version Fragmentation**: Classic vs Berry creates confusion
- ❌ **Would Discard Yemaya Config**: Existing pnpm setup would be abandoned

**Cost**: Low - Yarn is free **Risk**: Medium - PnP compatibility issues if
using Berry **Effort**: 3-4 days (need to convert Yemaya from pnpm)

### Option 3: npm Workspaces

**Description**: Native package manager bundled with Node.js with workspace
support added in npm v7+.

**Pros**:

- ✅ **Universal Availability**: Bundled with Node.js, no additional
  installation
- ✅ **No Migration**: Works with existing package-lock.json from Lilith
- ✅ **Familiar Commands**: Most developers know npm commands
- ✅ **Improving Performance**: npm v10+ significantly faster than earlier
  versions

**Cons**:

- ❌ **Disk Inefficient**: Full node_modules copy for each package, high disk
  usage
- ❌ **Slower Installs**: 2-3x slower than pnpm for monorepo installs
- ❌ **No Dependency Catalog**: Manual version management across packages
- ❌ **Phantom Dependencies**: Allows importing undeclared packages (hoisting
  side effect)
- ❌ **Lockfile Churn**: More frequent unnecessary changes to package-lock.json
- ❌ **Would Discard Yemaya Config**: Existing pnpm setup would be abandoned
- ❌ **Limited Monorepo Features**: Workspaces are basic compared to pnpm/Yarn

**Cost**: Free **Risk**: Medium - performance and phantom dependency issues at
scale **Effort**: 3-4 days (need to convert Yemaya from pnpm)

### Option 4: Bun

**Description**: All-in-one JavaScript runtime with built-in package manager,
bundler, and test runner.

**Pros**:

- ✅ **Extremely Fast**: 10-100x faster installs than npm in benchmarks
- ✅ **All-in-One**: Package manager, runtime, bundler, test runner
- ✅ **npm Compatible**: Uses existing package.json and node_modules structure
- ✅ **Native Workspaces**: Supports workspace protocol

**Cons**:

- ❌ **Immature**: Version 1.0 released recently, still stabilizing
- ❌ **Compatibility Issues**: Not all Node.js packages work correctly
- ❌ **Limited Monorepo Features**: No dependency catalog, basic workspace
  support
- ❌ **Nx Integration Uncertain**: Not officially supported by Nx
- ❌ **Production Risk**: Too new for critical production workloads
- ❌ **Team Unfamiliarity**: No existing experience with Bun

**Cost**: Free **Risk**: High - immature ecosystem, compatibility issues
**Effort**: 5+ days (extensive testing required)

## Decision Outcome

**Chosen option**: Option 1 - pnpm

**Justification**:

pnpm is the optimal choice for the Oshun monorepo for the following reasons:

1. **Existing Foundation**: Yemaya already has a mature, well-configured pnpm
   setup including:
   - Comprehensive pnpm-workspace.yaml with dependency catalog
   - Optimized .npmrc configuration with proper hoisting rules
   - Established patterns for workspace-internal dependencies

2. **Monorepo Excellence**: pnpm's design philosophy aligns perfectly with Nx
   monorepo patterns:
   - Content-addressable storage dramatically reduces disk usage
   - Strict dependency isolation prevents phantom dependency bugs
   - Dependency catalog feature enables centralized version management
   - Fast installs improve CI/CD pipeline performance

3. **Nx Integration**: Nx has excellent pnpm support:
   - `nx affected` works correctly with pnpm workspace structure
   - pnpm's deterministic installs complement Nx computation caching
   - Shared configuration patterns between Nx and pnpm

4. **Performance at Scale**: For a monorepo with 50+ packages:
   - Install times: pnpm ~30s vs npm ~90s vs Yarn ~60s (typical)
   - Disk usage: pnpm ~500MB vs npm ~1.5GB (typical)
   - CI/CD: Faster pipelines due to efficient caching

5. **Developer Safety**: pnpm's strictness catches errors early:
   - Cannot import packages not declared in package.json
   - Clear error messages for missing dependencies
   - Reproducible builds across environments

**Trade-offs Accepted**:

- Lilith developers need brief pnpm onboarding
- Some packages may need compatibility fixes for pnpm's strict mode
- Minor workflow adjustments for developers used to npm/yarn

**Implementation Plan**:

1. **Phase 1: Configuration Setup** (Day 1)
   - Create root pnpm-workspace.yaml incorporating all workspace paths
   - Create root .npmrc with optimized settings
   - Define comprehensive dependency catalog for shared versions

2. **Phase 2: Lilith Migration** (Day 1-2)
   - Remove yarn.lock and package-lock.json
   - Update package.json workspace configuration
   - Convert `workspace:*` protocol usage
   - Fix any hardcoded node_modules paths

3. **Phase 3: Unified Install** (Day 2)
   - Remove all node_modules directories
   - Run `pnpm install` at root
   - Resolve any peer dependency warnings
   - Verify all packages resolve correctly

4. **Phase 4: Verification** (Day 2-3)
   - Run builds for all packages
   - Run test suites
   - Verify Nx commands work correctly
   - Update CI/CD pipelines to use pnpm

**Success Metrics**:

- All packages install successfully with `pnpm install`
- No phantom dependency errors during build
- CI/CD install time < 60 seconds (with cache)
- Disk usage < 1GB for full node_modules
- All existing tests pass

**Review Schedule**: 30 days post-migration

## Implementation Details

### Technical Specifications

**Root pnpm-workspace.yaml Structure**:

```yaml
packages:
  # Oshun-level shared packages
  - 'libs/**/*'
  - 'apps/**/*'
  - 'tools/*'

  # Legacy Lilith packages (during migration)
  - 'lilith/packages/*'
  - 'lilith/services/*'
  - 'lilith/sdk/typescript'

  # Legacy Yemaya packages (during migration)
  - 'yemaya/packages/*'
  - 'yemaya/apps/*'
  - 'yemaya/configs/*'

catalog:
  # TypeScript toolchain
  typescript: '^6.0.3'
  tsup: '^8.0.2'
  tsx: '^4.7.1'

  # Testing
  vitest: '^2.0.0'
  '@vitest/coverage-v8': '^2.0.0'
  playwright: '^1.42.0'

  # Linting & Formatting
  eslint: '^9.0.0'
  prettier: '^3.2.5'

  # React ecosystem
  react: '^18.3.0'
  react-dom: '^18.3.0'

  # Node.js types
  '@types/node': '^20.12.0'

  # Validation
  zod: '^3.22.4'

  # Build tools
  vite: '^6.0.0'

  # Backend
  fastify: '^4.26.0'
  bullmq: '^5.34.0'
  ioredis: '^5.4.0'

  # Database
  prisma: '^5.10.0'
  '@prisma/client': '^5.10.0'
```

**Root .npmrc Configuration**:

```ini
# Dependency Resolution
strict-peer-dependencies=true
auto-install-peers=true
resolve-peers-from-workspace-root=true

# Hoisting Configuration
shamefully-hoist=true
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=vite
public-hoist-pattern[]=vitest
public-hoist-pattern[]=@nx/*

# Performance
store-dir=~/.pnpm-store
prefer-offline=true

# Scripts
enable-pre-post-scripts=true

# Registry
registry=https://registry.npmjs.org/

# Git
git-checks=true

# Lockfile
use-lockfile-v6=false
```

**Root package.json Structure**:

```json
{
  "name": "oshun",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "packageManager": "pnpm@10.25.0",
  "engines": {
    "node": ">=18.0.0",
    "pnpm": ">=9.0.0"
  },
  "scripts": {
    "build": "nx run-many -t build",
    "test": "nx run-many -t test",
    "lint": "nx run-many -t lint",
    "typecheck": "nx run-many -t typecheck",
    "clean": "nx reset && rimraf node_modules",
    "prepare": "husky"
  }
}
```

### Migration Strategy

**From**:

- Lilith: Yarn workspaces + npm hybrid
- Yemaya: pnpm standalone

**To**:

- Oshun: Unified pnpm workspace at root

**Migration Commands**:

```bash
# Step 1: Backup existing lock files
cp lilith/yarn.lock ~/lilith-yarn.lock.backup
cp lilith/package-lock.json ~/lilith-package-lock.backup
cp yemaya/pnpm-lock.yaml ~/yemaya-pnpm-lock.backup

# Step 2: Remove old package manager artifacts
rm -f lilith/yarn.lock
rm -f lilith/package-lock.json
rm -f yemaya/pnpm-lock.yaml

# Step 3: Remove all node_modules
find . -name "node_modules" -type d -prune -exec rm -rf {} +

# Step 4: Create root configuration
# (Create pnpm-workspace.yaml, .npmrc, package.json as specified above)

# Step 5: Install all dependencies
pnpm install

# Step 6: Verify installation
pnpm ls --depth 0
pnpm why <package-name>  # Debug specific packages
```

**Rollback Plan**: If critical issues discovered:

1. Remove root pnpm-lock.yaml and node_modules
2. Restore original lock files from backup
3. Reinstall with original package managers
4. Investigate issues before retrying

### Testing Strategy

**Pre-Migration Verification**:

- Capture current `npm ls` or `yarn list` output
- Record all package versions
- Run full test suite, record results

**Post-Migration Verification**:

- Compare package versions match pre-migration
- Run full test suite, compare results
- Verify build outputs are identical
- Test hot reload and development workflows
- Verify CI/CD pipeline runs successfully

## Consequences

### Positive Consequences

- ✅ **Unified Tooling**: Single package manager across entire monorepo
- ✅ **Disk Savings**: ~60% reduction in node_modules disk usage
- ✅ **Faster CI/CD**: Reduced install times improve pipeline efficiency
- ✅ **Dependency Safety**: Strict mode prevents phantom dependency bugs
- ✅ **Version Consistency**: Catalog ensures consistent versions across
  packages
- ✅ **Better Debugging**: Clear dependency graph aids troubleshooting
- ✅ **Nx Synergy**: Optimized integration with Nx workspace features

### Negative Consequences

- ❌ **Migration Effort**: One-time effort to convert Lilith packages
- ❌ **Learning Curve**: Developers need pnpm familiarity
- ❌ **Compatibility Work**: Some packages may need fixes for strict mode
- ❌ **Documentation Updates**: Contribution guides need updating

### Risks and Mitigation

| Risk                         | Probability | Impact | Mitigation Strategy                                              |
| ---------------------------- | ----------- | ------ | ---------------------------------------------------------------- |
| Package compatibility issues | Medium      | Medium | Test thoroughly, use `shamefully-hoist` for problematic packages |
| Developer productivity dip   | Low         | Low    | Provide pnpm cheat sheet, office hours for questions             |
| CI/CD pipeline failures      | Medium      | Medium | Test pipeline changes in separate branch first                   |
| Build output differences     | Low         | High   | Compare build artifacts before/after migration                   |

## Compliance and Security

### Security Implications

- **Lockfile Integrity**: pnpm-lock.yaml provides deterministic installs
- **Audit Support**: `pnpm audit` scans for vulnerabilities
- **Supply Chain**: Strict mode reduces attack surface from phantom dependencies
- **Reproducibility**: Content-addressable storage ensures identical packages

### Compliance Requirements

- **Deterministic Builds**: pnpm lockfile ensures reproducible installations
- **Audit Trail**: Package installation is fully logged
- **License Compliance**: `pnpm licenses` reports all dependency licenses

## Monitoring and Observability

### Metrics to Track

- **Install Time**: Track `pnpm install` duration in CI/CD
- **Disk Usage**: Monitor ~/.pnpm-store and node_modules sizes
- **Cache Hit Rate**: pnpm store cache effectiveness
- **Dependency Count**: Total dependencies across workspace

### Alerting Strategy

- **Install Failures**: Alert on `pnpm install` errors in CI
- **Security Vulnerabilities**: Weekly `pnpm audit` runs
- **Disk Growth**: Alert if store exceeds 5GB

## Related Decisions

### Upstream Dependencies

- **ADR-0001**: Git Repository Consolidation (single repo enables unified
  package management)
- **Nx Adoption**: Nx workspace requires consistent package manager

### Downstream Impacts

- **CI/CD Configuration**: Pipelines must use pnpm commands
- **Docker Builds**: Dockerfiles updated to use pnpm
- **Developer Setup**: Onboarding docs updated for pnpm
- **IDE Configuration**: VS Code/WebStorm settings for pnpm

## References

### External Resources

- [pnpm Documentation](https://pnpm.io/)
- [pnpm Workspace](https://pnpm.io/workspaces)
- [pnpm vs npm vs Yarn Benchmark](https://pnpm.io/benchmarks)
- [Nx + pnpm Integration](https://nx.dev/recipes/adopting-nx/adding-to-monorepo#using-pnpm)
- [Content-Addressable Storage Explained](https://pnpm.io/motivation)

### Internal Resources

- [ADR-0001: Git Repository Consolidation](./ADR-0001-git-repository-consolidation-strategy.md)
- Yemaya pnpm configuration — `yemaya/pnpm-workspace.yaml` (pre-consolidation
  source repo)
- Yemaya `.npmrc` — `yemaya/.npmrc` (pre-consolidation source repo)

---

## Revision History

| Version | Date       | Author           | Changes         |
| ------- | ---------- | ---------------- | --------------- |
| 1.0     | 2026-01-10 | Development Team | Initial version |
