Skip to main content
zerv is designed to run next to semantic-release, not instead of it. Split the work by branch:
  • semantic-release owns main. It reads conventional commits, decides the release version, writes the changelog, tags, and publishes.
  • zerv owns every other branch. Pull requests, feature branches, develop, release branches, dirty working trees: each Git state gets a SemVer on the spot, computed from tags, distance, branch, and dirtiness alone.
Release tools answer what version is this release? CI builds artifacts on every push, and those builds need versions long before a release exists. zerv answers what version is this exact Git state? The payoff: trunk-based development where every branch is still e2e-testable.
  • Every commit versioned - a version for any commit on any branch, including uncommitted changes. No build is ever unversioned.
  • Branch-based pre-releases - zerv flow maps branch patterns to pre-release types (develop and beta/* → beta, release/* → rc, everything else → alpha), so artifact names carry where they came from.
  • One payload, every format - generate ZERV RON once, then convert to SemVer, PEP440, CalVer, docker tags, v-prefixed major tags. Anything expressible as a schema or Tera template.

zerv vs semantic-release

zerv’s own repository runs both in its CD pipeline (cd.yml): semantic-release publishes the release, then zerv versions the same commit for artifact naming. The zerv-flow demonstration repo shows the full split. On pull requests, zerv runs alone: it versions the PR head, tags a pre-release, and feeds semver, PEP440, and docker tags to the deploy jobs. On main, semantic-release publishes and zerv versions the release build. See coexisting with semantic-release for the workflow wiring.

The core trade-off

zerv deliberately does not read commit messages or automate releases. It computes versions from VCS state (tags, distance, branch, dirtiness) and gets out of the way. That makes it:
  • Deterministic - the same Git state always yields the same version, regardless of commit message style.
  • Complementary - it runs alongside release automation instead of competing with it. See coexisting with semantic-release.
  • Language-agnostic - one Rust binary versions your Docker images, Python packages, Rust crates, and deployment manifests identically.

Same state, every format

One ZERV RON payload converts to whatever each pipeline stage needs:

zerv vs setuptools-scm

setuptools-scm versions Python packages at build time: the build backend reads Git state and writes the version into the package metadata. That is the right tool when the package itself is the only artifact. zerv versions every build in CI — Docker images, deployment manifests, Rust crates, npm packages — from the same Git state, with no Python build in the loop. If your pipeline only ever needs the version inside package metadata, stay with setuptools-scm.

zerv vs dunamai

dunamai is the closest tool in spirit: a Python library and CLI that produces standards-compliant versions from VCS tags, with an opinionated PEP 440 default. It even supports more version control systems than zerv (Mercurial, Subversion, Fossil, among others). The differences show up in CI for mixed stacks:
  • Runtime - zerv is one static Rust binary; dunamai needs a Python environment.
  • Branch semantics - zerv flow derives the pre-release label and number from branch patterns (develop → beta, release/* → rc); dunamai’s pre-release comes from the last tag, with the branch available only as a {branch} substitution in custom formats.
  • Output model - zerv can emit a ZERV RON payload once and re-render it into every format downstream; each dunamai invocation produces one string.

zerv vs git describe

git describe needs no install and prints v1.0.0-5-gabc1234 — distance and commit from the nearest tag. If that raw string is all your pipeline needs, use it. zerv starts where that shape stops: it parses the tag into version fields, normalizes to SemVer or PEP 440, derives pre-release segments from branch patterns (flow), and renders through schemas and Tera templates.

When to reach for something else

Last modified on September 16, 2026