dependency-upgrade
Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.
When & Why to Use This Skill
This Claude skill streamlines the complex process of managing major dependency upgrades using the Bun package manager. It enforces a systematic 'one-at-a-time' upgrade philosophy to prevent cascading failures, integrating compatibility analysis, breaking change research, and rigorous testing workflows to ensure codebase stability during modernization.
Use Cases
- Upgrading major frontend frameworks like React or Next.js by following a staged rollout and fixing breaking changes incrementally.
- Identifying and patching security-vulnerable dependencies while maintaining version compatibility across the project.
- Modernizing legacy codebases by systematically updating outdated libraries and resolving peer dependency conflicts.
- Managing large-scale dependency updates in monorepos using Bun's workspace filtering and recursive update features.
- Automating the discovery of breaking changes by integrating changelog research into the upgrade workflow.
| name | dependency-upgrade |
|---|---|
| description | Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries. |
Dependency Upgrade (Bun Edition)
Master major dependency version upgrades with Bun's blazing-fast package manager. This skill emphasizes one-at-a-time upgrades to prevent cascading failures and maintain control over breaking changes.
When to Use This Skill
- Upgrading major framework versions (React 17→18, Next.js 13→14, etc.)
- Updating security-vulnerable dependencies
- Modernizing legacy dependencies
- Resolving dependency conflicts
- Planning incremental upgrade paths
- Managing breaking changes systematically
Core Philosophy: One at a Time
NEVER upgrade all dependencies at once. This leads to:
- Impossible-to-debug failures
- Mixed breaking changes
- Unclear rollback points
- Test failures you can't isolate
ALWAYS upgrade one major dependency at a time:
- Pick ONE package
- Upgrade it
- Run tests
- Commit
- Repeat
Semantic Versioning Refresher
MAJOR.MINOR.PATCH (e.g., 2.3.1)
MAJOR: Breaking changes - requires code changes
MINOR: New features - backward compatible
PATCH: Bug fixes - backward compatible
^2.3.1 = >=2.3.1 <3.0.0 (allows minor & patch updates)
~2.3.1 = >=2.3.1 <2.4.0 (allows only patch updates)
2.3.1 = exactly 2.3.1 (locked version)
Dependency Discovery
Check What's Outdated (Fast!)
# See all outdated dependencies
bun outdated
# Output format:
# Package Current Update Latest
# react 17.0.2 17.0.2 18.2.0
# typescript 4.9.5 4.9.5 5.3.3
Filter by Package Pattern
# Check specific packages
bun outdated react react-dom
# Check all @types packages
bun outdated '@types/*'
# Check all eslint-related packages
bun outdated 'eslint*'
# Exclude certain patterns (! prefix)
bun outdated '!@types/*'
Workspace Support (Monorepos)
# Check one workspace
bun outdated --filter='@myapp/ui'
# Check multiple workspaces
bun outdated --filter='@myapp/*'
# Check all workspaces recursively
bun outdated --recursive
Upgrade Strategies
Strategy 1: Interactive Mode (Recommended for Beginners)
# Bun's built-in interactive selector
bun update -i
# This shows a checkbox list:
# ◯ react (17.0.2 → 18.2.0)
# ◯ typescript (4.9.5 → 5.3.3)
# ◯ eslint (8.0.0 → 8.56.0)
#
# Select ONE, press Enter, test, commit, repeat
Strategy 2: Manual One-at-a-Time (Recommended for Complex Upgrades)
# Step 1: Check what's available
bun outdated
# Step 2: Upgrade ONE package to latest (major version)
bun update react --latest
# Step 3: Install
# (Already installed by update command)
# Step 4: Run tests
bun test
# Step 5: Check types
bun tsc --noEmit
# Step 6: Run build
bun run build
# Step 7: If all pass, commit
git add package.json bun.lockb
git commit -m "chore: upgrade react to 18.2.0"
# Step 8: Repeat for next package
bun update react-dom --latest
Strategy 3: Using npm-check-updates (More Control)
# See what updates are available (no changes)
bunx npm-check-updates
# Interactive mode - choose which to upgrade
bunx npm-check-updates -i
# Update ONE package in package.json only
bunx npm-check-updates -u react
# Then install it
bun install
# Test, commit, repeat
Upgrade Workflow (Step-by-Step)
Phase 1: Preparation
# 1. Ensure clean git state
git status
# 2. Create upgrade branch
git checkout -b upgrade/react-18
# 3. Baseline: Run full test suite
bun test
bun run build
# 4. Tag current state (for easy rollback)
git tag pre-react-18-upgrade
# 5. Check what's outdated
bun outdated react react-dom
Phase 2: Research Breaking Changes
# Read the changelog (CRITICAL!)
# For React: https://react.dev/blog/2022/03/29/react-v18
# Common sources:
# - Official changelog/migration guide
# - GitHub releases
# - BREAKING.md or MIGRATION.md files
# Example: Check React changelog
bunx open-cli https://github.com/facebook/react/blob/main/CHANGELOG.md
Questions to answer:
- What APIs were deprecated/removed?
- What new APIs replace old ones?
- Are there codemods available?
- Do peer dependencies need updating?
Phase 3: Execute Upgrade (ONE Package)
# Upgrade the package
bun update react --latest
# Check what version was installed
bun pm ls react
# Expected: react@18.2.0 (or latest)
Phase 4: Fix Breaking Changes
# Run TypeScript to find type errors
bun tsc --noEmit
# Common React 17→18 changes:
# - ReactDOM.render → ReactDOM.createRoot
# - Automatic batching changes
# - Stricter StrictMode
# - New hooks (useId, useTransition, etc.)
Phase 5: Test Thoroughly
# Run unit tests
bun test
# Run type check
bun tsc --noEmit
# Run build
bun run build
# Check bundle size (important!)
bunx size-limit
# Run linter
bun run lint
# If you have E2E tests
bun run test:e2e
Phase 6: Commit and Continue
# If all tests pass
git add package.json bun.lockb
git commit -m "chore: upgrade react to 18.2.0
- Updated from 17.0.2 to 18.2.0
- Migrated ReactDOM.render to createRoot
- All tests passing"
# If tests fail
git reset --hard
# Fix issues, then commit
# Move to next package (e.g., react-dom)
bun update react-dom --latest
# Repeat phases 4-6
Advanced Techniques
Checking Peer Dependencies
# Bun automatically checks peer dependencies
# If there's a conflict, you'll see:
# warn: "react-dom@18.2.0" has peer dependency "react@^18.2.0"
# To see full dependency tree
bun pm ls react
bun pm ls --all | grep react
# Check why a package is installed
bun why react
Dealing with Transitive Dependencies
# See what depends on an outdated package
bun why old-package
# If a dependency of a dependency is outdated:
# 1. Check if updating the parent fixes it
bun update parent-package --latest
# 2. If not, use resolutions in package.json
{
"resolutions": {
"vulnerable-package": "^2.0.0"
}
}
Using Codemods for Automated Fixes
# React upgrades
bunx react-codemod \
--parser tsx \
--transform new-jsx-transform \
src/
# Rename unsafe lifecycles
bunx react-codemod \
--parser tsx \
--transform rename-unsafe-lifecycles \
src/
# Next.js upgrades
bunx @next/codemod <transform>
# General purpose codemod runner
bunx jscodeshift -t transform.js src/
Batch Checking (Not Upgrading!) Multiple Packages
# Check React ecosystem together
bun outdated react react-dom @types/react @types/react-dom
# Check TypeScript ecosystem
bun outdated typescript @types/node ts-node
# But STILL upgrade one at a time!
Security Audits
# Check for vulnerabilities
bun audit
# Auto-fix vulnerabilities (safe minor/patch updates)
bun audit --fix
# For major version security fixes, upgrade manually
bun outdated
bun update vulnerable-package --latest
Rollback Strategies
Quick Rollback
# If you tagged before upgrading
git reset --hard pre-react-18-upgrade
# Restore dependencies
bun install
Selective Rollback
# Revert package.json changes
git checkout HEAD -- package.json bun.lockb
# Reinstall
bun install
Emergency Rollback (Production)
# Deploy previous version
git revert <upgrade-commit-hash>
# Or redeploy from previous tag
git checkout v1.2.3
Common Upgrade Patterns
Pattern 1: Framework + Ecosystem
# Example: Upgrading React
# Order matters! Upgrade in dependency order:
# 1. TypeScript first (if used)
bun update typescript --latest
bun tsc --noEmit
git commit -am "chore: upgrade typescript to 5.3.3"
# 2. React core
bun update react --latest
bun test
git commit -am "chore: upgrade react to 18.2.0"
# 3. React DOM (must match React version)
bun update react-dom --latest
bun test
git commit -am "chore: upgrade react-dom to 18.2.0"
# 4. React types
bun update @types/react @types/react-dom --latest
bun tsc --noEmit
git commit -am "chore: upgrade react types"
# 5. Testing library
bun update @testing-library/react --latest
bun test
git commit -am "chore: upgrade testing library"
# 6. React Router (if used)
bun update react-router-dom --latest
bun test
git commit -am "chore: upgrade react-router-dom to 6.x"
Pattern 2: Build Tools
# Example: Vite upgrade
bun update vite --latest
bun update @vitejs/plugin-react --latest
bun run build
git commit -am "chore: upgrade vite and plugins"
Pattern 3: Linting/Formatting
# These are usually safe to upgrade together
# (but still test!)
bun update eslint --latest
bun update prettier --latest
bun run lint
git commit -am "chore: upgrade linting tools"
Testing Checklist
After EACH upgrade:
- [ ] TypeScript compiles (`bun tsc --noEmit`)
- [ ] Unit tests pass (`bun test`)
- [ ] Build succeeds (`bun run build`)
- [ ] Dev server works (`bun run dev`)
- [ ] Linter passes (`bun run lint`)
- [ ] No console errors/warnings
- [ ] Bundle size acceptable
- [ ] Key features tested manually
- [ ] E2E tests pass (if applicable)
Tools Comparison
Bun Native (Recommended)
Pros:
- Blazing fast (written in Zig)
- Built-in, no extra dependencies
- Interactive mode with
-i --latestflag for major versions- Workspace support
- Clean, readable output
Cons:
- Newer than npm-check-updates
- Fewer configuration options
Use for: Most upgrades, especially in Bun projects
bun update -i
npm-check-updates (Alternative)
Pros:
- Battle-tested, mature
- Extensive filtering options
.ncurc.jsconfig files- Large community
- Advanced target modes (minor, patch, latest)
Cons:
- Extra dependency (though bunx makes it easy)
- Slightly slower
Use for: Complex filtering needs, legacy projects, or when you need .ncurc configs
bunx npm-check-updates -i
Recommendation: Default to bun update -i for simplicity and speed. Use npm-check-updates when you need advanced filtering or config files.
Automation (With Caution!)
Automated Checks (Safe)
# .github/workflows/dependencies.yml
name: Dependency Check
on:
schedule:
- cron: '0 9 * * 1' # Monday 9am
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: bun outdated
Dependabot for Minor/Patch Only
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
# Limit concurrent PRs
open-pull-requests-limit: 3
# Group minor/patch updates
groups:
dependencies:
patterns:
- "*"
update-types:
- "minor"
- "patch"
CRITICAL: Configure Dependabot to NEVER auto-merge major updates. Always review and test major version changes manually.
Troubleshooting
Peer Dependency Conflicts
# Error: "react-router-dom@6.0.0" has peer dependency "react@^18.0.0"
# Solution 1: Update peer dependency first
bun update react --latest
# Solution 2: Use overrides in package.json (last resort)
{
"overrides": {
"react": "^18.0.0"
}
}
Lock File Conflicts
# If bun.lockb is corrupted
rm bun.lockb
bun install
# If git merge conflict in lockfile
# Accept one version, then regenerate:
git checkout --theirs bun.lockb
bun install
Bundle Size Increased Significantly
# Check what increased
bunx vite-bundle-visualizer
# Or for Next.js
bunx @next/bundle-analyzer
# Consider:
# - Tree shaking configuration
# - Dynamic imports
# - Check if new version includes more by default
# - Rolling back if increase is unacceptable
Breaking Changes Are Too Complex
# Don't skip major versions!
# Go incrementally: 16 → 17 → 18
# Example: React 16 → 18
bun update react@17 react-dom@17 --latest
bun test
git commit -am "chore: upgrade react to 17"
bun update react@18 react-dom@18 --latest
bun test
git commit -am "chore: upgrade react to 18"
Tests Pass Locally but Fail in CI
# Clear CI cache
# In GitHub Actions: delete and re-create caches
# Ensure lockfile is committed
git add bun.lockb
git commit -m "chore: update lockfile"
# Use frozen lockfile in CI
# In CI script:
bun install --frozen-lockfile
Useful Scripts (Add to package.json)
{
"scripts": {
"deps:check": "bun outdated",
"deps:interactive": "bun update -i",
"deps:audit": "bun audit",
"deps:why": "bun why",
"upgrade:react": "bun update react react-dom @types/react @types/react-dom --latest",
"upgrade:next": "bun update next @types/node --latest",
"upgrade:typescript": "bun update typescript @types/node --latest",
"test:upgrade": "bun test && bun tsc --noEmit && bun run build && bun run lint",
"ncu": "bunx npm-check-updates",
"ncu:interactive": "bunx npm-check-updates -i",
"ncu:check": "bunx npm-check-updates --target latest"
}
}
Then use like:
# Interactive upgrade
bun run deps:interactive
# Check React updates
bun run deps:check react react-dom
# Full upgrade test suite
bun run test:upgrade
Common Dependency Upgrade Orders
React Application
1. typescript → TypeScript compiler
2. react → Core React library
3. react-dom → React DOM bindings
4. @types/react, @types/react-dom → Type definitions
5. @testing-library/react → Testing utilities
6. react-router-dom → Routing (if used)
7. Build tools (vite, webpack, etc.)
8. Linting (eslint, prettier)
Next.js Application
1. typescript → TypeScript compiler
2. next → Next.js framework
3. react, react-dom → Updated by Next.js peer deps
4. @types/node, @types/react → Type definitions
5. Build plugins (if any)
6. Linting tools
Node.js/Bun Backend
1. typescript → TypeScript compiler
2. Core framework (express, fastify, hono, etc.)
3. Database drivers
4. Authentication libraries
5. Type definitions
6. Testing tools
7. Linting tools
Real-World Example: React 17 → 18
# Step 1: Check current state
bun outdated react react-dom
# Output:
# react 17.0.2 17.0.2 18.2.0
# react-dom 17.0.2 17.0.2 18.2.0
# Step 2: Read migration guide
# https://react.dev/blog/2022/03/29/react-v18
# Step 3: Create branch
git checkout -b upgrade/react-18
git tag pre-react-18
# Step 4: Upgrade React
bun update react --latest
# ✓ Installed react@18.2.0
# Step 5: Upgrade React DOM (must match)
bun update react-dom --latest
# ✓ Installed react-dom@18.2.0
# Step 6: Update types
bun update @types/react @types/react-dom --latest
# Step 7: Fix breaking changes
# Change in src/index.tsx:
# OLD:
# ReactDOM.render(<App />, document.getElementById('root'))
#
# NEW:
# const root = ReactDOM.createRoot(document.getElementById('root')!)
# root.render(<App />)
# Step 8: Test
bun test
bun tsc --noEmit
bun run build
bun run dev # Manual testing
# Step 9: Commit
git add .
git commit -m "chore: upgrade react to 18.2.0
- Updated react and react-dom from 17.0.2 to 18.2.0
- Migrated from ReactDOM.render to createRoot API
- Updated type definitions
- All tests passing"
# Step 10: Update testing library (if needed)
bun update @testing-library/react --latest
bun test
git commit -am "chore: upgrade testing library for React 18"
Best Practices Summary
- One at a Time: Never upgrade multiple major dependencies simultaneously
- Read Changelogs: Always read breaking changes before upgrading
- Test Thoroughly: Run full test suite after EACH upgrade
- Commit Frequently: One commit per major dependency
- Use Branches: Create feature branches for upgrade work
- Tag Before: Tag your repo before starting upgrades
- Check Peer Deps: Ensure peer dependencies are compatible
- Watch Bundle Size: Monitor bundle size changes
- Incremental Majors: Go 16→17→18, not 16→18
- Have Rollback Plan: Know how to revert quickly
- Use
--latest: Required to upgrade beyond semver range - Interactive Mode: Use
-ito see and select updates
The Golden Rule
If you upgrade 10 packages and tests fail, you have no idea which one caused it.
If you upgrade 1 package and tests fail, you know exactly what to fix.
Always upgrade dependencies one at a time. Your future self will thank you.