Skip to main content
Version: Next

One repository or many

dispat does not decide whether you keep everything in one repository or give each project its own. This page explains the differences between the two setups. It covers which differences dispat removes and how you can move between them without losing your published versions.

dispat works either way. It exists because the release side of a monorepo is genuinely harder, and it is perfectly happy in a repository holding one thing.

The two shapes​

One repository. Every project is a folder. You get one checkout, one history, and one CI configuration. You have one place to change something that crosses two projects.

A repository each. Every project is its own repository with its own history, permissions, and pipeline. Projects talk to each other only through published versions.

Both are legitimate, and plenty of teams run a mixture. They use a repository per product, and each repository holds the several packages that make up the product.

What each one costs​

One repositoryA repository each
A change crossing two projectsone commit, one review, one CI runone pull request per repository, merged in the right order
Knowing what works with whatthe checkout is a tested combinationyou find out when someone installs the published versions
Release orderingthe tool's problem, if the tool understands the graphyours, by hand or by waiting
Access controlmostly all or nothingper repository, naturally
Checkout and CI costgrows with the whole repository unless jobs are selectivesmall, always
Release pipelines to maintainoneone per repository
Independent cadenceneeds per-package versionsfree

Read that table as the honest version of the argument. A monorepo trades convenience across projects for size and coupling. Separate repositories trade coordination cost for independence.

Which of those costs dispat removes​

dispat targets exactly three rows of that table.

Release ordering. dispat reads the dependency graph in one repository and releases in topological order. A library publishes before the service that consumes it, and packages with no relation publish in parallel. You do not schedule that by hand.

Independent cadence in one repository. Each package keeps its own version, tag, and changelog. One commit can release one package, several packages, or the whole repository, which stops a monorepo from meaning that everything ships at once. Shared versions covers the opposite choice for packages that should move together.

CI cost. A monorepo only gets expensive if every job does everything. Run dispat run --since and dispat if --changed to execute a script only in the packages a change reached. This includes dependants, so the pipeline scales with the diff rather than with the repository.

Without a control repository, each dispat run still sees one repository and one graph.

Joining repositories through a control checkout​

Independent runs cannot order releases or propagate a version between two projects in different repositories. There is no graph spanning those runs.

Separate repositories mean the only connection is a published version, and picking that version up is the consumer's own decision. This is the definition of the choice rather than a gap to work around. A bot like Renovate opens a pull request for dispat to release, and the reconciliation pickup handles this situation automatically inside one repository.

You can get the graph back without merging histories by using a repository that holds the control configuration and links the sources as git submodules. In source-history mode, dispat reads each source's commits and tags under one fixed gitlink snapshot. In pointer-history mode, control commits describe pointer moves. Both modes order releases and propagate versions across the combined graph while the code stays where it is. A control repository for many repositories explains this pattern and its costs.

Joining repositories as peers​

You do not have to add a control repository to get the graph. With a repository identity, every repository is a peer that optionally names the others in its repositories roster and keeps its own configuration and release records, two-sided submodule links join the peers, and a run started in any of them composes the whole fleet. The trade is symmetry against central control: no commit can address the fleet as a whole, because every unit is read against the repository that carries it. A choreographed fleet explains the keys, the links and the boundaries.

dispat in a single-project repository​

dispat does not require more than one package. A repository delivering one thing declares one standalone entry to get automatic versioning, changelogs, tags, and releases from its commits. A single package shows this setup in full.

Two details are different at that size:

  • Set tagFormat: "v{version}" to get v1.4.0 rather than app@1.4.0. You do not need the prefix because there is no second package to disambiguate from.
  • Set path to . when the manifest, the sources and the changelog live at the top of the repository: the package is then the repository itself, and its scripts run there. See The repository as the package. Set it to a directory such as src, lib, or app when the deliverable sits in one, in which case the root-manifest example runs npm commands from the root while source changes belong to the configured folder.

A fleet of small repositories each running dispat is a completely ordinary setup. Every repository gets its own release lock. The lock is a tag on that repository's own remote, so they never wait for each other.

Moving from many repositories to one​

The work is mostly git, and the dispat portion is one command.

  1. Bring the histories together using git subtree add or a plain copy so each project ends up in its own folder.
  2. Write a config naming the folders. Keeping configuration beside the code shows a layout where each space and package holds its own file to keep a big repository readable.
  3. Run dispat compute --write. It reads the manifests and writes the dependencies edges between the packages, alongside the initials each package starts from. This ensures you do not lose the versions you already published.
  4. Run dispat status before you release anything. It reports what a release would do and changes nothing.

The versions carry over because a baseline is a tag or an initials entry. Both survive the move. Adopting dispat shows the same procedure with transcripts.

Moving from one repository to many​

The reverse is no harder. Extract the folder into its own repository, and keep the tags for that package if the history came with it, or state initials if it did not. The package's next release continues from the version it was on rather than starting at zero.

Separate dispat runs lose ordering and propagation between the split-off project and what remains. A control repository can retain them by linking both sources and declaring the cross-repository edge. This is an extra shared pipeline and lock, so choose it only when that coordination is useful.

Choosing​

These questions decide the shape faster than a general argument:

  • Do changes routinely touch two projects at once? If yes, one repository saves you the coordination every time.
  • Do the projects release on genuinely unrelated schedules, for unrelated audiences? If yes, separate repositories cost you little.
  • Does anybody need access to one project and not the others? This is the strongest argument for separate repositories. It is also the hardest to work around.
  • Is the repository large enough that a full checkout is a problem? Measure before deciding. It usually happens later than people expect.
  • Are you splitting to make releases simpler? This is the one reason worth re-examining. dispat already handles the release complexity.

Where to go next​

  • From one package to many walks through growth in one repository. You start with one deliverable today and add four more later without restructuring.
  • Examples provides a complete setup per ecosystem. Most of them are a handful of lines.
  • Concepts explains versions, propagation, and channels. The rest of the documentation uses this vocabulary.