Multi-repo & monorepos
You'll learn:
- The four workspace topologies Versionx supports.
- How to coordinate commands across many repos.
- How atomic cross-repo releases work via the saga protocol.
Prerequisites: Versionx installed.
The four topologies
Versionx recognizes these workspace shapes:
- Single repo — one git root, one
versionx.toml. Default. - Submodule monorepo — one outer repo, many
git submodule-linked inner repos. - Subtree monorepo — one outer repo, inner content imported via
git subtree. - Virtual monorepo — many independent repos described in a shared fleet config.
- Ref monorepo — branches of the same repo represent different packages (rare; for migration scenarios).
The workspace layer lives in versionx-multirepo. Each topology has its own handler; the top-level API is the same.
Declaring the topology
In versionx.toml:
[workspace]
topology = "submodule" # or subtree / virtual / ref / single
members = ["apps/*", "packages/*"]
For virtual monorepos, reference the fleet config:
[workspace]
topology = "virtual"
inherit = ["fleet://acme-platform/baseline"]
[members]
app-api = { git = "https://github.com/acme/app-api", ref = "main" }
app-web = { git = "https://github.com/acme/app-web", ref = "main" }
worker = { git = "https://github.com/acme/worker", ref = "main" }
Running commands across repos
Every command takes --scope:
versionx status --scope workspace # default for monorepos
versionx status --scope fleet # every repo Versionx knows about
versionx status --scope members:apps/web,apps/api # explicit members
Per-repo output is merged and consistent regardless of topology.
Parallelism
versionx update --plan --scope fleet --jobs 8
Each member runs in its own process; Versionx deduplicates tool invocations and caches what it can. Defaults to num_cpus::get().min(8).
Atomic cross-repo releases (the saga protocol)
To release a feature that spans several repos:
versionx release plan --scope members:app-api,app-web,worker
Produces a single saga plan. Apply runs as a saga:
- Prepare — verify every member can be released (git clean, lockfiles synced, policy green).
- Commit — on every member in order defined by the dep graph.
- Tag — every member.
- Push — every member. Any failure triggers compensating rollbacks.
- Record — state DB captures the saga ID so the run is auditable.
If the saga fails at step 4 after 2 of 3 pushes succeed, Versionx runs compensating commands on the successful pushes to either delete the tag or mark the run as failed — your policy decides. See Policy & waivers.
Fleet config
Living in a dedicated ops repo (e.g., acme/platform-ops):
# platform-ops/versionx-fleet.toml
[fleet]
name = "acme-platform"
[runtimes]
node = "22"
python = "3.13"
[policies]
default = "acme-platform/baseline.policy.toml"
[members]
# Every repo in the fleet lists itself here.
app-api = { git = "https://github.com/acme/app-api" }
app-web = { git = "https://github.com/acme/app-web" }
Members opt in with [workspace] inherit = ["fleet://..."] in their own versionx.toml.
TUI dashboard
For interactive work:
versionx tui
The Dashboard view shows every repo Versionx is aware of, their release status, outstanding updates, policy state, and current runtime pins. Drill in to see the event log for any member. See Daemon & TUI.
Troubleshooting
- A saga stuck after partial push.
versionx saga statusshows the saga ID and step.versionx saga compensate <id>runs the compensation logic manually. - Member not discovered. Fleet config points to a repo that isn't reachable.
versionx fleet doctoraudits connectivity and permissions. - Different members have conflicting pins.
versionx fleet diffshows drift.
See also
- Orchestrating a release — release semantics for a single repo.
- Policy & waivers — enforce rules that span members.