Skip to content

Monorepo Support ​

bumpx provides comprehensive support for monorepo projects, allowing you to manage versions across multiple packages with flexible strategies.

Overview ​

Monorepos present unique challenges for version management:

  • Multiple packages with different release cycles
  • Interdependent packages requiring coordinated releases
  • Maintaining version consistency across related packages
  • Managing git operations across the entire repository

bumpx handles these scenarios with sophisticated detection and management capabilities.

Package Discovery ​

Automatic Workspace Detection ​

bumpx now includes first-class workspace support with automatic detection from your workspaces field in package.json:

bash
# Automatic workspace detection
bumpx patch

# Explicit recursive mode with workspace detection
bumpx patch --recursive

# See what packages would be updated
bumpx patch --dry-run --verbose

bumpx intelligently detects workspace configurations from:

  • NPM workspaces: "workspaces": ["packages/*"]
  • Yarn workspaces: "workspaces": { "packages": ["packages/*"] }
  • PNPM workspaces: Works with pnpm-workspace.yaml
  • Fallback: Traditional recursive directory scanning

Manual Package Selection ​

Target specific packages:

bash
# Update specific packages
bumpx patch --files packages/core/package.json,packages/cli/package.json

# Use glob patterns
bumpx minor --files "packages/*/package.json"
bumpx patch --files "apps/*/package.json,libs/*/package.json"

Exclude Packages ​

Skip certain packages from updates:

bash
# Update all except documentation packages
bumpx patch --files "packages/*/package.json" --exclude "**/docs/**"

# Custom selection logic
find packages -name "package.json" -not -path "*/test-*/*" | \
  xargs bumpx patch --files

Versioning Strategies ​

Independent Versioning ​

Each package maintains its own version and release cycle:

bash
# Bump each package from its current version
bumpx patch --recursive

# Shows current versions before bumping
bumpx minor --recursive --verbose

Example Output:

📦 packages/core/package.json: 1.2.3 → 1.3.0
📦 packages/cli/package.json: 2.1.0 → 2.2.0
📦 packages/utils/package.json: 0.5.2 → 0.6.0

Synchronized Versioning ​

All packages share the same version:

bash
# Set all packages to the same version
bumpx patch --recursive --current-version 1.0.0

# Bump all packages to a specific version
bumpx 2.0.0 --recursive

Example Output:

📦 packages/core/package.json: 1.2.3 → 2.0.0
📦 packages/cli/package.json: 2.1.0 → 2.0.0
📦 packages/utils/package.json: 0.5.2 → 2.0.0

Hybrid Approach ​

Combine strategies for different package groups:

bash
# Sync core packages
bumpx patch --files "packages/core*/package.json" --current-version 1.0.0

# Independent versioning for apps
bumpx patch --files "apps/*/package.json"

# Tools maintain separate versions
bumpx minor --files "tools/*/package.json"

Workspace Configurations ​

NPM Workspaces ​

bumpx works seamlessly with NPM workspaces:

json
{
  "name": "my-monorepo",
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}
bash
# Update all workspace packages
bumpx patch --recursive

# Respect workspace configuration
npm run build --workspaces
bumpx minor --recursive --execute "npm run build --workspaces"

Yarn Workspaces ​

Compatible with Yarn workspace configurations:

json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": {
    "packages": ["packages/*", "tools/*"]
  }
}
bash
# Update and build all workspaces
bumpx patch --recursive --execute "yarn workspaces run build"

Pnpm Workspaces ​

Works with pnpm workspace setups:

yaml
# pnpm-workspace.yaml
packages:

  - 'packages/*'
  - 'apps/*'
  - '!**/test/**'
bash
# Update all packages
bumpx patch --recursive

# Run scripts across workspace
bumpx minor --recursive --execute "pnpm run build --recursive"

Lerna Integration ​

Integrate with Lerna-managed repositories:

bash
# Use bumpx instead of lerna version
bumpx patch --recursive --commit --tag

# Combine with Lerna publishing
bumpx minor --recursive --commit --tag --execute "lerna publish from-package"

Dependency Management ​

Internal Dependencies ​

Handle packages that depend on each other:

json
{
  "name": "@myorg/app",
  "dependencies": {
    "@myorg/core": "^1.2.0",
    "@myorg/utils": "^0.5.0"
  }
}
bash
# Update all packages, preserving dependency relationships
bumpx patch --recursive

# Update dependencies to match new versions
bumpx patch --recursive --execute "npm update @myorg/*"

Version Range Updates ​

Automatically update internal dependency ranges:

bash
# Custom script to update dependency versions
cat > scripts/update-deps.js << 'EOF'
const fs = require('fs');
const glob = require('glob');

// Find all package.json files
const packages = glob.sync('packages/*/package.json');

packages.forEach(pkgPath => {
  const pkg = JSON.parse(fs.readFileSync(pkgPath));

  // Update internal dependencies
  if (pkg.dependencies) {
    Object.keys(pkg.dependencies).forEach(dep => {
      if (dep.startsWith('@myorg/')) {
        pkg.dependencies[dep] = '^' + process.env.NEW*VERSION;
      }
    });
  }

  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
});
EOF

# Use in version bump workflow
NEW*VERSION=$(bumpx patch --dry-run | grep "→" | head -1 | awk '{print $3}')
bumpx patch --recursive --execute "NEW*VERSION=$NEW*VERSION node scripts/update-deps.js"

Git Operations in Monorepos ​

Unified Commits ​

Create single commits for monorepo releases:

bash
# Single commit for all package updates
bumpx patch --recursive --commit --message "chore: release all packages to %s"

# Include package details in commit
bumpx minor --recursive --commit --verbose

Selective Commits ​

Commit packages separately:

bash
# Commit each package separately
for package in packages/*/package.json; do
  dir=$(dirname "$package")
  name=$(basename "$dir")
  bumpx patch --files "$package" --commit --message "chore($name): release v%s"
done

Tag Strategy ​

Different tagging approaches for monorepos:

bash
# Single tag for entire monorepo
bumpx patch --recursive --current-version 1.0.0 --tag --tag-message "monorepo-v%s"

# Package-specific tags
bumpx patch --files packages/core/package.json --tag --tag-message "core-v%s"
bumpx patch --files packages/cli/package.json --tag --tag-message "cli-v%s"

Release Workflows ​

Coordinated Releases ​

Release all packages together:

bash
# !/bin/bash
# scripts/release.sh

set -e

echo "🚀 Starting monorepo release..."

# Ensure clean state
git status --porcelain | wc -l | xargs test 0 -eq

# Run tests
npm run test --workspaces

# Update versions
bumpx patch --recursive --commit --tag

# Build all packages
npm run build --workspaces

# Push release
git push origin main --tags

echo "✅ Release complete!"

Selective Releases ​

Release only changed packages:

bash
# !/bin/bash
# scripts/selective-release.sh

# Find packages with changes since last release
CHANGED*PACKAGES=$(git diff --name-only HEAD~1 | grep "packages/" | cut -d'/' -f1-2 | sort -u)

for package*dir in $CHANGED*PACKAGES; do
  if [ -f "$package*dir/package.json" ]; then
    echo "Releasing $package*dir..."
    bumpx patch --files "$package*dir/package.json" --commit --tag
  fi
done

git push origin main --tags

Canary Releases ​

Create prerelease versions for testing:

bash
# Create canary releases for all packages
bumpx prerelease --preid canary --recursive --commit

# Create alpha releases with timestamp
TIMESTAMP=$(date +%Y%m%d%H%M%S)
bumpx prerelease --preid "alpha.$TIMESTAMP" --recursive --commit

Advanced Configurations ​

Conditional Updates ​

Update packages based on conditions:

bash
# !/bin/bash
# Only update packages that have changes

git diff --name-only HEAD~1 | while read file; do
  if [[ $file == packages/*/package.json ]]; then
    package*dir=$(dirname "$file")
    echo "Updating $package*dir due to changes"
    bumpx patch --files "$file" --commit
  elif [[ $file == packages/*/* ]]; then
    package*dir=$(echo "$file" | cut -d'/' -f1-2)
    package*json="$package*dir/package.json"
    if [ -f "$package*json" ]; then
      echo "Updating $package*dir due to file changes"
      bumpx patch --files "$package*json" --commit
    fi
  fi
done

Version Constraints ​

Ensure version relationships:

bash
# !/bin/bash
# Ensure core package version >= other packages

CORE*VERSION=$(jq -r '.version' packages/core/package.json)

for package in packages/*/package.json; do
  if [[ $package != "packages/core/package.json" ]]; then
    PACKAGE*VERSION=$(jq -r '.version' "$package")

# Compare versions (simplified)
    if [[ "$PACKAGE*VERSION" > "$CORE*VERSION" ]]; then
      echo "Warning: $package version $PACKAGE*VERSION > core version $CORE*VERSION"
# Optionally fix the constraint
      bumpx "$CORE*VERSION" --files "$package"
    fi
  fi
done

Build Order Dependencies ​

Handle build order requirements:

bash
# !/bin/bash
# Release packages in dependency order

# Define build order
PACKAGES=("packages/utils" "packages/core" "packages/cli" "apps/web")

for package*dir in "${PACKAGES[@]}"; do
  if [ -f "$package*dir/package.json" ]; then
    echo "Building and releasing $package*dir..."

# Build package
    cd "$package*dir"
    npm run build
    cd - > /dev/null

# Update version
    bumpx patch --files "$package*dir/package.json" --commit
  fi
done

git push origin main --tags

Configuration Examples ​

Monorepo Configuration ​

Shared configuration for monorepo:

typescript
// bumpx.config.ts
export default {
  recursive: true,
  commit: true,
  tag: false,
  push: false,
  message: 'chore: release packages',
  execute: 'npm run build --workspaces && npm run test --workspaces',
  files: [
    'packages/*/package.json',
    'apps/*/package.json'
  ]
}

Or in package.json:

json
{
  "name": "my-monorepo",
  "bumpx": {
    "recursive": true,
    "commit": true,
    "tag": false,
    "push": false,
    "message": "chore: release packages",
    "execute": "npm run build --workspaces && npm run test --workspaces",
    "files": [
      "packages/*/package.json",
      "apps/*/package.json"
    ]
  }
}

Package-Specific Configuration ​

Different configs for different package types:

typescript
// packages/core/bumpx.config.ts
export default {
  tag: true,
  tagMessage: 'core-v%s',
  execute: 'npm run build && npm run test:integration'
}
typescript
// packages/cli/bumpx.config.ts
export default {
  tag: true,
  tagMessage: 'cli-v%s',
  execute: 'npm run build && npm run test:e2e'
}

Or in each package's package.json:

json
// packages/core/package.json
{
  "name": "@myorg/core",
  "bumpx": {
    "tag": true,
    "tagMessage": "core-v%s",
    "execute": "npm run build && npm run test:integration"
  }
}

Best Practices ​

Version Strategy Guidelines ​

  1. Independent for different domains: Use independent versioning for packages serving different purposes
  2. Synchronized for related packages: Use synchronized versioning for tightly coupled packages
  3. Semantic versioning: Follow semver strictly for public packages
  4. Prerelease testing: Use prereleases for testing across the monorepo

Release Process ​

  1. Test thoroughly: Run comprehensive tests across all packages
  2. Update dependencies: Ensure internal dependencies are updated
  3. Document changes: Maintain changelogs for each package
  4. Automate where possible: Use scripts to reduce manual errors

Git Strategy ​

  1. Single repository: Keep all related packages in one repository
  2. Clear commit messages: Use conventional commits with package scopes
  3. Proper tagging: Use consistent tag naming conventions
  4. Branch protection: Protect main branch and require reviews

Troubleshooting ​

Common Issues ​

Version conflicts:

bash
# Check for version mismatches
find packages -name "package.json" -exec jq '.version' {} \; | sort | uniq -c

# Force consistency
bumpx patch --recursive --current-version 1.0.0

Missing packages:

bash
# Verify package discovery
bumpx patch --recursive --dry-run --verbose

# Check file patterns
ls packages/*/package.json

Build failures:

bash
# Test build before release
npm run build --workspaces || exit 1
bumpx patch --recursive --commit

Dependency issues:

bash
# Update all dependencies after version bump
npm update
npm audit fix

# Verify workspace consistency
npm ls --workspaces