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.
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.
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
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
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.
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.
- 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.