Skip to content

Instantly share code, notes, and snippets.

@shykes
Created May 30, 2026 05:39
Show Gist options
  • Select an option

  • Save shykes/a4673369c9a6d9994f62646cd02949f0 to your computer and use it in GitHub Desktop.

Select an option

Save shykes/a4673369c9a6d9994f62646cd02949f0 to your computer and use it in GitHub Desktop.
Proposal: versions.toml as source of truth for intended versions

Versions in versions.toml

Problem

To build and release Dagger, we compute and inject a version string. We do this in a way that is slow, breaks separation of concerns, and increases complexity and bugs.

Specifically, the current implementation:

  • Fetches all Git tags on each build, making it slower and vulnerable to GitHub outages.
  • Walks Git tags to compute the version, which is slow and gets worse as history grows.
  • Injects the version via custom ldflags, leaking project-specific details into reusable orchestration modules.
  • Treats Git tags as release inputs, which is backwards: release-by-promotion should promote an already-validated commit, but the current flow requires a tag before the release exists.
  • Accumulates complex custom code in the release pipeline, where bugs are expensive and hard to test.

Solution

Introduce a committed versions.toml as the source of truth for intended versions.

Example:

["cmd/dagger"]
version = "1.2.3"

["sdk/go"]
version = "0.17.0"

["sdk/python"]
version = "0.17.0"

At build time, the build:

  • Reads the intended version from versions.toml.
  • Reads commit and dirty state from native VCS metadata.
  • Skips ldflags injection entirely.
  • Never inspects Git tags.

A build knows:

version = 1.2.3
commit  = 42424242
dirty   = false

A build does not know whether it is an official release. Release status is determined separately, through a release manifest or release service.

Version format

Builds report version in three forms.

Human-readable:

version: 1.2.3
commit:  42424242
dirty:   no

Canonical build identifier:

1.2.3+42424242

Dirty build:

1.2.3+42424242.dirty

CLI

Default:

$ dagger version
version: 1.2.3
commit:  42424242
dirty:   no

Machine-readable:

$ dagger version -q
1.2.3+42424242

Release lookup:

$ dagger version --check
version: 1.2.3
commit:  42424242
dirty:   no

released:         yes
update-available: yes
latest-version:   1.2.4

Release flow

A release is a promotion of a previously validated commit:

commit
  ↓
CI validation
  ↓
artifact creation
  ↓
promotion to release
  ↓
tag / manifest update

Tags become release records, not release inputs.

Standardization opportunity

The versions.toml format is generic and applies beyond Dagger.

Semantics:

path    = artifact/component identity
version = intended base version

A build derives its identity from three sources:

version  from versions.toml
commit   from VCS metadata
dirty    from VCS metadata

Release status is out of scope. Any artifact — binary, SDK, library, container — can share this version source without build-time injection.

Benefits

  • Eliminates Git tag traversal at build time.
  • Removes custom ldflags from orchestration modules.
  • Keeps the release pipeline free of project-specific logic.
  • Enables release-by-promotion: a release records a validated commit instead of triggering one.
  • Simplifies the release pipeline, where bugs are expensive and hard to test.
  • Uses native VCS metadata for commit and dirty state.
  • Makes version intent explicit, committed, and reviewable in source control.
  • Scales naturally to monorepos by mapping paths to versions.
  • Generalizes to a format that could be adopted outside Dagger.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment