Skip to main content

Monorepo Support

Versionator supports monorepos with multiple packages that need independent versioning. Each package can have its own VERSION file, and versionator automatically discovers the correct one based on your working directory.

How It Works

Versionator walks up the directory tree from your current working directory to find the nearest VERSION file. This enables:

  • Independent versions: Each package has its own version
  • Workspace versions: Groups of related packages can share a version
  • Root version: A project-wide version at the repository root

Directory Structure Example

myproject/
├── VERSION # 1.0.0 (root project version)
├── .versionator.yaml # Root config

├── packages/
│ ├── VERSION # 2.0.0 (packages workspace)
│ ├── .versionator.yaml # Packages config
│ │
│ ├── core/
│ │ ├── VERSION # 3.0.0
│ │ ├── package.json
│ │ └── src/
│ │
│ ├── utils/
│ │ ├── VERSION # 1.5.0
│ │ ├── package.json
│ │ └── src/
│ │
│ └── cli/ # No VERSION - inherits from packages/
│ ├── package.json
│ └── src/

└── apps/
└── web/
├── VERSION # 0.1.0
└── src/

Working with Packages

Check Version

# From myproject/packages/core/
versionator output version
# Output: 3.0.0

# From myproject/packages/cli/ (no VERSION file)
versionator output version
# Output: 2.0.0 (from packages/VERSION)

# From myproject/
versionator output version
# Output: 1.0.0

Bump Package Version

cd packages/core
versionator minor increment
# packages/core/VERSION: 3.1.0

cd ../utils
versionator patch increment
# packages/utils/VERSION: 1.5.1

Release Individual Packages

cd packages/core
versionator release
# Creates tag: core-v3.1.0 and branch release/core-v3.1.0 (if prefix configured)

Configuration Inheritance

Each directory level can have its own .versionator.yaml:

# packages/.versionator.yaml
prefix: "v"
prerelease:
template: "alpha-{{CommitsSinceTag}}"

The nearest config file is used for that directory.

Common Patterns

Workspace-Level Versioning

Group related packages under a single VERSION:

packages/
├── VERSION # Shared version: 2.0.0
├── @myorg/core/
├── @myorg/utils/
└── @myorg/cli/

All packages in this workspace share the same version.

Independent Package Versioning

Each package has its own VERSION:

packages/
├── core/
│ └── VERSION # 3.0.0
├── utils/
│ └── VERSION # 1.5.0
└── cli/
└── VERSION # 2.1.0

Root + Package Versioning

Root version for the overall project, separate versions for packages:

myproject/
├── VERSION # 1.0.0 (overall project)
├── packages/
│ ├── core/
│ │ └── VERSION # Independent: 3.0.0
│ └── utils/
│ └── VERSION # Independent: 1.5.0
└── apps/ # Uses root VERSION
└── web/

CI/CD Integration

Matrix Builds

Run version commands per package in CI:

# GitHub Actions
jobs:
version-packages:
strategy:
matrix:
package: [core, utils, cli]
steps:
- uses: actions/checkout@v4
- name: Get version
working-directory: packages/${{ matrix.package }}
run: echo "VERSION=$(versionator version)" >> $GITHUB_OUTPUT

Conditional Releases

Only release packages that changed:

- name: Check for version change
run: |
if git diff HEAD~1 --name-only | grep -q "packages/core/VERSION"; then
echo "RELEASE_CORE=true" >> $GITHUB_ENV
fi

Best Practices

  1. Consistent prefixes: Use the same prefix convention across packages
  2. Clear directory structure: Group related packages together
  3. Version at the right level: Don't create unnecessary VERSION files
  4. Document versioning strategy: Make clear which packages are independently versioned

Generating Version Files

Generate version files for each package:

# Generate Python version file for each package
for pkg in core utils cli; do
cd packages/$pkg
versionator output emit python --output src/_version.py
cd ../..
done

See Also