Dependency Management
Safe and systematic approach to updating dependencies while maintaining stability and security.
When to Use This Skill
Use when:
- •User asks to "update dependencies" or "upgrade packages"
- •Monthly/quarterly dependency maintenance
- •Security vulnerability alerts (CVEs)
- •Before major feature releases
- •Package manager shows outdated dependencies
- •User mentions: "Are our dependencies up to date?"
Core Principles
- •Security First: Update packages with known vulnerabilities immediately
- •Test-Driven: Never update without running full test suite
- •Incremental: Update one category at a time (prod → dev → tooling)
- •Semantic Versioning: Understand patch/minor/major implications
- •Documented: Track what changed and why
- •Reversible: Always commit before updates for easy rollback
Pre-Update Checklist
Before starting any dependency updates:
- • Commit all current work:
git statusshould be clean - • All tests currently passing
- • Create update branch:
git checkout -b chore/dependency-updates-YYYY-MM - • Review project documentation for current stack
- • Check for breaking changes in major version updates
Semantic Versioning Strategy
Understanding version numbers: MAJOR.MINOR.PATCH
| Update Type | Example | Risk | Testing |
|---|---|---|---|
| Patch | 5.1.0 → 5.1.1 | Low | Run tests |
| Minor | 5.1.0 → 5.2.0 | Medium | Test thoroughly + manual QA |
| Major | 5.0.0 → 6.0.0 | High | Review changelog, expect code changes |
Update strategy:
- •Patch updates: Generally safe, apply automatically
- •Minor updates: Review changelog, test thoroughly
- •Major updates: Plan separately, may require code changes
Universal Workflow
Step 1: Audit Current Dependencies
JavaScript/TypeScript (npm):
npm audit # Security vulnerabilities npm outdated # Outdated packages
Python (pip):
pip list --outdated # Outdated packages pip-audit # Security vulnerabilities (if installed) # Or: pip install safety && safety check
Rust (cargo):
cargo outdated # Requires: cargo install cargo-outdated cargo audit # Requires: cargo install cargo-audit
Go (go mod):
go list -u -m all # Outdated modules # Or: go install github.com/psampaz/go-mod-outdated@latest go list -u -m all | go-mod-outdated -update -direct
Ruby (bundler):
bundle outdated # Outdated gems bundle audit # Security vulnerabilities
Step 2: Update Dependency Manifest
JavaScript/TypeScript (package.json):
# Interactive update npx npm-check-updates # Preview npx npm-check-updates -u # Update package.json # Targeted update npm install package-name@latest npm install -D dev-package@latest
Python (requirements.txt or pyproject.toml):
# Manual edit for pyproject.toml # Change: package>=1.0.0 to package>=1.1.0 # For requirements.txt pip install --upgrade package-name pip freeze > requirements.txt
Rust (Cargo.toml):
# Manual edit # Change: package = "1.0" to package = "1.1" # Or use cargo-edit cargo install cargo-edit cargo upgrade # Interactive upgrade
Go (go.mod):
go get -u package-name # Update specific package go get -u ./... # Update all direct dependencies go mod tidy # Clean up
Ruby (Gemfile):
# Update Gemfile manually or: bundle update package-name # Specific gem bundle update # All gems (careful!)
Step 3: Install/Update Dependencies
JavaScript/TypeScript:
npm install # Install updated packages npm ci # Clean install (CI/prod)
Python:
pip install -r requirements.txt # Install from requirements pip install -e . # Install from pyproject.toml
Rust:
cargo update # Update Cargo.lock cargo build # Verify builds
Go:
go mod download # Download modules go mod verify # Verify integrity
Ruby:
bundle install # Install updated gems
Step 4: Run Tests (MANDATORY)
DO NOT SKIP TESTING
JavaScript/TypeScript:
npm test # All tests npm test -- --coverage # With coverage npm run lint # Linting npm run type-check # TypeScript
Python:
python -m pytest # All tests python -m pytest --cov # With coverage pylint src/ # Linting mypy . # Type checking
Rust:
cargo test # All tests cargo test --all-features # With all features cargo clippy # Linting
Go:
go test ./... # All tests go test -cover ./... # With coverage go vet ./... # Code analysis golangci-lint run # Comprehensive linting
Ruby:
bundle exec rspec # All tests bundle exec rubocop # Linting
Step 5: Manual Testing
Test critical paths:
- • Application starts without errors
- • Core features work as before
- • No console/log errors
- • Performance unchanged/better
- • Build succeeds (if applicable)
Step 6: Review Changes
# Check what actually changed git diff package.json # JavaScript git diff pyproject.toml # Python git diff Cargo.toml # Rust git diff go.mod # Go git diff Gemfile.lock # Ruby # Look for: # - Major version jumps (review breaking changes) # - New transitive dependencies # - Removed dependencies
Step 7: Commit Changes
git add package.json package-lock.json # JavaScript git add pyproject.toml requirements.txt # Python git add Cargo.toml Cargo.lock # Rust git add go.mod go.sum # Go git add Gemfile Gemfile.lock # Ruby git commit -m "chore(deps): update dependencies - Updated production dependencies (patch/minor/major) - Updated dev dependencies - All tests passing (X passed) - No breaking changes / Breaking changes: [list] - Security fixes: [CVEs if applicable]"
Security Updates (High Priority)
When security vulnerabilities are detected:
1. Assess Severity
# JavaScript npm audit # Python safety check pip-audit # Rust cargo audit # Review: # - Severity (low/moderate/high/critical) # - Exploitability (is your code affected?) # - Patch availability
2. Update Affected Packages
Targeted security updates:
JavaScript:
npm audit fix # Auto-fix compatible updates npm audit fix --force # Force major updates (review changes!)
Python:
pip install --upgrade vulnerable-package
Rust:
cargo update -p vulnerable-package
Go:
go get -u vulnerable-package@latest go mod tidy
3. Test Immediately
Security updates should be tested and deployed ASAP:
- •Run full test suite
- •Quick manual smoke test
- •Deploy to staging
- •Monitor for issues
- •Deploy to production
Rollback Procedure
If updates break something:
Option 1: Revert Commit
git revert HEAD # Creates new commit undoing changes npm install # Reinstall old versions
Option 2: Reset Branch
git reset --hard origin/main # Nuclear option: lose all changes npm install # Reinstall
Option 3: Selective Rollback
# JavaScript: Restore old package.json git checkout HEAD~1 package.json package-lock.json npm install # Python: Restore old requirements git checkout HEAD~1 requirements.txt pip install -r requirements.txt # Rust: Restore old Cargo files git checkout HEAD~1 Cargo.toml Cargo.lock cargo build # Go: Restore old go.mod git checkout HEAD~1 go.mod go.sum go mod download
Common Scenarios
Scenario 1: Monthly Maintenance
Goal: Keep dependencies reasonably up-to-date
# 1. Check for updates npm outdated / pip list --outdated / cargo outdated # 2. Update patch/minor versions npx npm-check-updates -u --target minor npm install && npm test # 3. Plan major updates separately # (Review changelogs, schedule dedicated time)
Scenario 2: Security Alert
Goal: Fix vulnerability ASAP
# 1. Identify vulnerable package npm audit / pip-audit / cargo audit # 2. Update to patched version npm install vulnerable-package@patched-version # 3. Test immediately npm test # 4. Deploy ASAP if tests pass
Scenario 3: Pre-Release Prep
Goal: Fresh dependencies before release
# 1. Update all dev dependencies npm update --dev / pip install -U -r requirements-dev.txt # 2. Update non-breaking prod dependencies npm update / pip install -U package # 3. Test extensively npm test && npm run e2e # 4. Document updates in changelog
Best Practices
Do:
- •✅ Update dependencies regularly (monthly/quarterly)
- •✅ Read changelogs for major updates
- •✅ Run tests after EVERY update
- •✅ Update one category at a time (prod → dev → peer)
- •✅ Commit after each successful category update
- •✅ Document breaking changes in commit message
- •✅ Use lockfiles (package-lock.json, Cargo.lock, go.sum)
Don't:
- •❌ Update everything at once ("big bang" approach)
- •❌ Skip testing after updates
- •❌ Use exact version pins unless required (npm/pip)
- •❌ Ignore security vulnerabilities
- •❌ Update during feature development
- •❌ Force major updates without reviewing changes
Lockfile Management
Purpose of lockfiles:
- •Ensure reproducible builds
- •Lock transitive dependency versions
- •Enable reliable CI/CD
When to commit lockfiles:
- •✅ Always commit: package-lock.json (npm), Cargo.lock (Rust), go.sum (Go), Gemfile.lock (Ruby)
- •⚠️ Libraries only: Don't commit lockfiles for libraries (let consumers choose versions)
- •✅ Applications always: Always commit lockfiles for applications
Troubleshooting
Issue: Tests Fail After Update
- •Read test output carefully
- •Check updated package changelogs for breaking changes
- •Search GitHub issues for the package
- •Update code to match new API
- •If unfixable, rollback and plan migration
Issue: Dependency Conflicts
JavaScript:
npm install --legacy-peer-deps # Ignore peer dep conflicts (temporary) npm ls package-name # See dependency tree
Python:
pip install package --no-deps # Skip dependency check (dangerous!) pipdeptree # Visualize dependency tree
Rust:
# Edit Cargo.toml to resolve version conflicts cargo tree # View dependency tree
Issue: Build Breaks After Update
- •
Clear caches and rebuild:
bashnpm ci # JavaScript (clean install) cargo clean # Rust go clean -modcache # Go
- •
Check for deprecated APIs in changelog
- •
Update code to use new APIs
- •
Verify toolchain compatibility (Node.js version, Rust version, etc.)
Related Skills
- •tdd-workflow - Test after updates
- •refactoring-workflow - Update code for new APIs
- •validation-troubleshooting - Fix test failures
This skill is framework-agnostic. Patterns apply to JavaScript, Python, Rust, Go, Ruby, Java, C#, or any language with a package manager.