Skip to content

Migrate from Yarn Classic to pnpm for improved monorepo support #2120

@justin808

Description

@justin808

Summary

Migrate from Yarn Classic 1.22.22 to pnpm for better monorepo support, faster installs, and native workspace linking that eliminates the need for yalc.

Context

This issue supersedes the "stay with Yarn" decision from #2088, which was made when yalc was still critical to our workflow. Now that #2089 plans to remove yalc (post-monorepo merger), the main argument for staying with Yarn Classic is gone.

Why Now?

  1. yalc removal is planned (Remove yalc #2089) - The main blocker for pnpm is being removed
  2. Monorepo maturity - The monorepo structure is stabilizing (Phase 5 complete, Phase 6-8 in progress)
  3. Clean slate opportunity - Better to migrate during the restructuring than after

Current Pain Points with Yarn Classic + yalc

  1. Manual yalc publish required after changes
  2. Not integrated into monorepo workflow
  3. Additional tool dependency
  4. Requires .yalc directory and lock file management
  5. Can cause confusion when packages get out of sync
  6. Yarn Classic is in maintenance mode (no new features)

Benefits of pnpm

1. Native Workspace Linking (Replaces yalc)

# In package.json, use workspace protocol
"dependencies": {
  "react-on-rails": "workspace:*"
}

# Changes automatically linked - no manual publish step!

2. Faster Installs

  • Content-addressable storage
  • Hard links instead of copies
  • Typically 2-3x faster than Yarn Classic

3. Better Disk Usage

  • Packages shared across projects
  • Single global store instead of per-project copies

4. Selective Operations

# Build specific package
pnpm --filter react-on-rails build

# Build all packages recursively
pnpm -r build

# Run tests in one package
pnpm --filter react-on-rails-pro test

5. Strict Dependencies

  • Prevents phantom dependencies
  • Catches missing peer deps early
  • More reliable builds

6. Industry Adoption

  • Used by Vue, Vite, Turborepo, and many major monorepos
  • Active development with frequent releases
  • Growing community and ecosystem support

Migration Plan

Prerequisites

Phase 1: Preparation (1 hour)

  • Create pnpm-migration branch
  • Install pnpm: npm install -g pnpm
  • Import lockfile: pnpm import (converts yarn.lock to pnpm-lock.yaml)

Phase 2: Configuration (2 hours)

  • Create .npmrc with pnpm settings:
    # Hoist patterns for packages that expect flat node_modules
    shamefully-hoist=false
    strict-peer-dependencies=true
    auto-install-peers=true
  • Update package.json:
    • Set "packageManager": "pnpm@9.x.x"
    • Update workspaces config if needed (syntax is compatible)
  • Update workspace package dependencies to use workspace:* protocol:
    "dependencies": {
      "react-on-rails": "workspace:*"
    }

Phase 3: Script Updates (2 hours)

  • Update package-scripts.yml:
    • Replace yarn with pnpm
    • Update workspace commands to use pnpm --filter
  • Update Rakefile and rakelib/ scripts
  • Update CI workflows (.github/workflows/)
  • Update bin/ scripts

Phase 4: CI Configuration (2 hours)

  • Update GitHub Actions to use pnpm:
    - uses: pnpm/action-setup@v2
      with:
        version: 9
    - name: Install dependencies
      run: pnpm install --frozen-lockfile
  • Update cache configuration for pnpm store
  • Test all CI workflows pass

Phase 5: Documentation (1 hour)

  • Update CLAUDE.md development commands
  • Update CONTRIBUTING.md
  • Update README.md installation instructions
  • Update .conductor/ workspace docs
  • Remove all yalc-related documentation

Phase 6: Cleanup (30 min)

  • Remove yarn.lock
  • Remove .yalc/ directories
  • Remove yalc.lock files
  • Remove yalc from devDependencies
  • Update .gitignore

Phase 7: Validation (1 hour)

  • Run full test suite: pnpm test
  • Run linting: pnpm lint
  • Test package builds: pnpm -r build
  • Test in spec/dummy apps
  • Verify workspace linking works correctly
  • Test clean install from scratch

Testing Checklist

Before merging, verify:

  • pnpm install completes successfully
  • pnpm -r build builds all packages
  • Workspace packages are properly linked:
    cd packages/react-on-rails-pro
    ls -la node_modules/react-on-rails  # Should be symlink
  • Changes propagate automatically (no manual publish needed)
  • All CI workflows pass
  • Example apps work
  • Ruby gem builds correctly
  • NPM packages publish correctly (test with pnpm pack)

Rollback Plan

If issues arise post-migration:

  1. Restore yarn.lock from git history
  2. Remove pnpm-lock.yaml
  3. Revert script changes
  4. Run yarn install

The yarn.lock can be preserved in a branch for 30 days before deletion.

Estimated Effort

Phase Time
Preparation 1 hour
Configuration 2 hours
Script Updates 2 hours
CI Configuration 2 hours
Documentation 1 hour
Cleanup 30 min
Validation 1 hour
Total ~10 hours

Risks and Mitigations

Risk 1: Tool Compatibility

Risk: Some tools may not support pnpm
Mitigation: pnpm is widely supported; can use shamefully-hoist=true as fallback

Risk 2: CI Cache Invalidation

Risk: Initial CI runs will be slower without cache
Mitigation: pnpm's subsequent runs are faster; cache will rebuild quickly

Risk 3: Team Learning Curve

Risk: Developers unfamiliar with pnpm
Mitigation: Similar commands to yarn; good documentation; minimal mental model shift

Risk 4: Shakapacker Compatibility

Risk: Shakapacker may have yarn-specific assumptions
Mitigation: Shakapacker uses npm client detection; test thoroughly in dummy apps

Success Criteria

  • No yalc usage anywhere in the repo
  • All workspace packages use workspace:* protocol
  • Single pnpm install sets up entire monorepo
  • Changes in one package immediately visible in dependent packages
  • CI is faster or equivalent to current setup
  • All tests pass
  • Documentation is updated

Dependencies

References

Labels

enhancement, dependencies

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions