Versioning
Modules follow Semantic Versioning (SemVer): MAJOR.MINOR.PATCH.
| Component | When to increment | Example |
|---|---|---|
| MAJOR | Breaking changes | Port schema changes, removed components |
| MINOR | New features (backward compatible) | New components, new ports |
| PATCH | Bug fixes (backward compatible) | Performance improvements, bug fixes |
Where a Version Lives
One release touches the same version string in four places, with one deliberate asymmetry — git tags carry the v, everything else is bare:
| Location | Form | Example |
|---|---|---|
| Git tag (triggers the release workflow) | v prefix | v1.2.3 |
| Image tag on GHCR | bare | ghcr.io/my-org/my-module:1.2.3 |
module.yaml versions: entry in the module repo | bare | version: 1.2.3 |
run --version / cli.versionID ldflag | bare | 1.2.3 |
The workflow strips the prefix (version=${GITHUB_REF_NAME#v}), and the module binary refuses to start with a v-prefixed --version. If you see a v anywhere but the git tag, something is wrong.
The Index Is the Version Source
Consumers never resolve versions from git or GHCR directly. The versions: array in module.yaml — folded into the repo's index.yaml by tiny repo index — is what tiny install my-module (latest) or tiny install my-module@1.2.3 (pinned) resolves against:
name: my-module
source: github.com/my-org/my-module
versions:
- version: 1.2.3
image: ghcr.io/my-org/my-module:1.2.3
chart: tinysystems/tinysystems-operator
chartVersion: 0.2.10
Publishing a version = pushing the image and adding this entry, then regenerating the index. An image that exists on GHCR but isn't in any index is invisible.
Each version also pins the chartVersion of the shared operator chart it installs with, so a chart change rolls out per module version, deliberately.
Toolchain Versions
| What | Version |
|---|---|
| Go | 1.25+ |
SDK (github.com/tiny-systems/module) | v0.13.x line |
| Builder image | golang:1.25 |
Update the SDK with:
go get github.com/tiny-systems/module@latest
go mod tidy
The SDK version a module was built with is embedded in the binary (via Go build info) and reported in the TinyModule/TinyNode status as sdkVersion — useful when debugging behavior differences across installed modules.
Module Names and Versions
The module name (--name, the index key, the image repo) does not embed the version — versions live in the versions: array. References to a module in cluster state are bare (no publisher prefix): http-module, not tinysystems/http-module. The runtime's name matching is tolerant of legacy prefixed forms in both directions, so existing nodes keep working, but write new references bare.
Releasing
# Tag and push — CI does the rest of the image side
git tag -a v1.2.3 -m "Release v1.2.3"
git push origin v1.2.3
# Then update the module repo: module.yaml + regenerated
# components.yaml / values.yaml + `tiny repo index`
Rules of thumb:
- Never reuse or move a tag — publish a new patch instead.
- Keep old entries in the
versions:array; consumers may pin them. - A breaking port-schema change is a MAJOR bump: existing flows reference your ports by name and shape.
Pre-releases
SemVer pre-release suffixes (1.0.0-rc.1) work in tags and image labels, but keep them out of the public index until stable — a versions: entry is an invitation to install.
Next Steps
- Building Modules - Build process
- Registry Publishing - Publish to an index
- The Shared Operator Chart - Deployment