Dependency Upgrade Planner
Plans safe dependency upgrades by checking changelogs, breaking changes, peer dependency conflicts, and suggesting an upgrade order.
Dependency Upgrade Planner
Plan and execute safe dependency upgrades with risk assessment, breaking change analysis, compatibility verification, and rollback strategies for Node.js, Python, and other ecosystems.
When to Use This Template
Choose Dependency Upgrade Planner when:
- You have outdated dependencies and need a prioritized upgrade plan
- A major version upgrade requires breaking change analysis and code modifications
- Security vulnerabilities require immediate but safe dependency updates
- You want to batch compatible upgrades to minimize CI runs and risk
Consider alternatives when:
- You need automated PR creation for dependency updates (use Dependabot or Renovate)
- You need to audit dependencies for license compliance (use license-checker)
- You are evaluating new dependencies to add (use bundlephobia or npm-compare)
Quick Start
# .claude/skills/dependency-upgrade-planner.yml name: dependency-upgrade-planner description: Plan safe dependency upgrades with risk analysis prompt: | Analyze the project's dependencies and create an upgrade plan. For each dependency: 1. Current version vs latest version 2. Changelog analysis for breaking changes 3. Risk assessment (low/medium/high) 4. Required code changes 5. Upgrade order (respect peer dependencies) 6. Rollback strategy Group upgrades into safe batches that can be tested independently.
Example invocation:
claude "Create an upgrade plan for all outdated dependencies"
Sample upgrade plan:
Dependency Upgrade Plan
āāāāāāāāāāāāāāāāāāāāāā
Outdated: 23 packages (5 major, 11 minor, 7 patch)
Security: 2 critical, 1 high
Batch 1 ā Security Fixes (deploy ASAP)
axios: 0.21.1 ā 1.7.4 [CRITICAL: SSRF vulnerability]
Breaking: Response.data typing changed
Code changes: Update 3 files (type imports)
lodash: 4.17.19 ā 4.17.21 [HIGH: Prototype pollution]
Breaking: None
Code changes: None required
Batch 2 ā Patch Updates (safe, no breaking changes)
typescript: 5.3.2 ā 5.3.3
eslint: 8.56.0 ā 8.57.0
prettier: 3.2.1 ā 3.2.5
... (4 more)
Batch 3 ā Minor Updates (new features, backwards compatible)
next: 14.1.0 ā 14.2.15
Note: New caching behavior ā test SSR pages
react-query: 5.17.0 ā 5.62.0
Note: New devtools features
Batch 4 ā Major Updates (breaking changes, needs code mods)
next: 14.2.15 ā 15.1.0 [MAJOR]
Breaking: App Router changes, new Image component API
Code changes: ~15 files need updating
Risk: HIGH ā thorough testing required
Core Concepts
Risk Assessment Matrix
| Factor | Low Risk | Medium Risk | High Risk |
|---|---|---|---|
| Version jump | Patch (x.x.1ā2) | Minor (x.1ā2.x) | Major (1ā2.x.x) |
| Dependents | 0-2 files use it | 3-10 files | 10+ files or core |
| Breaking changes | None listed | API additions | API removals/changes |
| Test coverage | > 80% covered | 50-80% covered | < 50% covered |
| Ecosystem maturity | 1M+ weekly downloads | 100K+ downloads | < 100K downloads |
Upgrade Analysis Script
// analyze-upgrades.js const { execSync } = require('child_process'); function analyzeUpgrades() { // Get outdated packages const outdated = JSON.parse( execSync('npm outdated --json 2>/dev/null || echo "{}"').toString() ); const plan = { security: [], patch: [], minor: [], major: [] }; for (const [name, info] of Object.entries(outdated)) { const current = info.current; const latest = info.latest; const wanted = info.wanted; // Check for security vulnerabilities const auditOutput = execSync( `npm audit --json 2>/dev/null || echo "{}"` ).toString(); const audit = JSON.parse(auditOutput); const hasVulnerability = audit.vulnerabilities?.[name]; // Determine upgrade type const [curMajor, curMinor] = current.split('.').map(Number); const [latMajor, latMinor] = latest.split('.').map(Number); const upgrade = { name, current, latest, wanted, vulnerability: hasVulnerability?.severity || null, type: latMajor > curMajor ? 'major' : latMinor > curMinor ? 'minor' : 'patch' }; if (hasVulnerability) { plan.security.push(upgrade); } else { plan[upgrade.type].push(upgrade); } } return plan; } // Count files that import each dependency function countDependents(packageName) { try { const result = execSync( `grep -rl "from '${packageName}\\|require('${packageName}" src/ --include='*.ts' --include='*.tsx' --include='*.js' | wc -l` ).toString().trim(); return parseInt(result) || 0; } catch { return 0; } }
Safe Upgrade Workflow
# Step 1: Create upgrade branch git checkout -b deps/batch-1-security-fixes # Step 2: Upgrade specific package npm install axios@latest # Step 3: Check for breaking changes npx npm-check-updates --filter axios --format repo # Opens the changelog in the browser # Step 4: Run type check npx tsc --noEmit # Step 5: Run tests npm test # Step 6: If everything passes, commit git add package.json package-lock.json git commit -m "fix: upgrade axios to 1.7.4 (SSRF vulnerability fix)" # Step 7: If something breaks, rollback git checkout -- package.json package-lock.json npm install
Peer Dependency Resolution
// Build upgrade order respecting peer dependencies function buildUpgradeOrder(packages: Package[]): Package[][] { const batches: Package[][] = []; const upgraded = new Set<string>(); while (upgraded.size < packages.length) { const batch: Package[] = []; for (const pkg of packages) { if (upgraded.has(pkg.name)) continue; // Check if all peer dependencies are already upgraded const peersSatisfied = (pkg.peerDependencies || []) .every(peer => upgraded.has(peer) || !packages.find(p => p.name === peer)); if (peersSatisfied) { batch.push(pkg); } } if (batch.length === 0) { // Circular dependency ā upgrade remaining together batch.push(...packages.filter(p => !upgraded.has(p.name))); } batch.forEach(p => upgraded.add(p.name)); batches.push(batch); } return batches; }
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
includeDevDeps | boolean | true | Include devDependencies in analysis |
securityOnly | boolean | false | Only plan security-related upgrades |
maxBatchSize | number | 5 | Maximum packages per upgrade batch |
riskThreshold | string | "medium" | Maximum risk level for auto-upgrade: low, medium, high |
lockfileUpdate | boolean | true | Update lockfile after each batch |
testCommand | string | "npm test" | Command to verify after upgrade |
Best Practices
-
Upgrade security vulnerabilities first and separately ā Security patches have the highest urgency and usually the lowest risk (patch versions). Create a dedicated PR for security fixes so they can be reviewed, approved, and deployed quickly without being blocked by unrelated upgrade work.
-
Batch compatible upgrades together ā Group patch updates into a single PR, minor updates into another, and handle each major update individually. This keeps PRs reviewable and makes it easy to identify which upgrade caused a regression if tests fail.
-
Read changelogs for major upgrades, not just release notes ā The npm page shows the latest version's notes, but the migration guide (usually in the repo's MIGRATION.md or UPGRADING.md) covers all breaking changes between your current version and the target. Skipping intermediate breaking changes causes subtle bugs.
-
Lock exact versions for production dependencies ā Use
npm install --save-exactor setsave-exact=truein.npmrcto prevent unexpected updates when colleagues runnpm install. Controlled upgrades are always safer than implicit ones through semver ranges. -
Keep a dependency decision log ā Document why specific versions are pinned, why certain upgrades are deferred, and what workarounds exist for known issues. This prevents future developers from upgrading a pinned dependency without understanding the constraint, and helps onboarding.
Common Issues
Peer dependency conflicts block installation ā Package A requires react@^17 while package B requires react@^18, making both uninstallable. Use npm install --legacy-peer-deps temporarily, then check if package A has a newer version compatible with React 18. If not, file an issue upstream and document the pin in your dependency decision log.
Lockfile conflicts after upgrade ā Two developers upgrade different packages on separate branches, causing massive lockfile merge conflicts. Never manually resolve lockfile conflicts. Delete the lockfile, run npm install to regenerate it, then verify the installed versions match expectations. Alternatively, use npm install on the merged branch and commit the regenerated lockfile.
Tests pass locally but fail in CI after upgrade ā The CI environment may have a different Node.js version, different OS (Linux vs macOS), or cached node_modules from a previous run. Ensure CI clears caches after dependency upgrades, uses the same Node version specified in .nvmrc or engines, and runs npm ci (clean install) instead of npm install.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.