Skip to main content

Version Grammar

This guide explains how version strings work in plain English. Whether you're tagging releases, configuring CI/CD, or just trying to understand what v1.2.3-beta.1+build.456 means, this page has you covered.

For the formal specification, see the EBNF grammar file.

What is a Version String?​

A version string is a structured way to communicate information about a software release. Instead of saying "the new version" or "the February update," version strings provide precise, comparable identifiers.

v1.2.3-beta.1+build.456

This single string tells us:

  • It's version 1.2.3
  • It's a beta pre-release (the first one)
  • It was built with identifier "build.456"

Anatomy of a Version​

Every version string follows this pattern:

[prefix]MAJOR.MINOR.PATCH[-prerelease][+metadata]

Let's break down each part:

The Prefix (Optional)​

v1.0.0
V2.3.4
1.0.0

The prefix is a single letter that appears before the numbers. Versionator only allows:

PrefixMeaning
vLowercase "v" (most common)
VUppercase "V"
(none)No prefix at all

Why only v/V? This follows conventions established by Go modules, npm, and git tags. Other prefixes like "ver" or "version-" are not supported because they create inconsistency across tools.

The Core Version (Required)​

The core version has three numbers separated by dots:

MAJOR.MINOR.PATCH
ComponentWhat It MeansWhen to Change
MAJORBreaking changesYou changed something that breaks existing code
MINORNew featuresYou added something new (backwards compatible)
PATCHBug fixesYou fixed a bug (backwards compatible)

Examples:

VersionInterpretation
1.0.0First stable release
2.0.0Major rewrite or breaking changes from 1.x
1.5.0Added new features to version 1
1.5.3Third bug fix release for version 1.5

The rules:

  • All three numbers are required
  • Numbers can be any non-negative integer (0, 1, 2, ... 999, etc.)
  • No leading zeros (use 1.2.3, not 01.02.03)

Pre-release Identifier (Optional)​

Pre-release versions come before the final release. They're for testing and early access.

1.0.0-alpha
1.0.0-beta.1
1.0.0-rc.2

The pre-release starts with a hyphen (-) followed by identifiers separated by dots.

Common pre-release labels:

LabelMeaningTypical Use
alphaVery early, unstableInternal testing
betaFeature complete, may have bugsExternal testing
rcRelease candidateFinal testing before release

Adding numbers:

You can add numbers to track iterations:

1.0.0-alpha      # First alpha
1.0.0-alpha.1 # Alpha iteration 1
1.0.0-alpha.2 # Alpha iteration 2
1.0.0-beta # Move to beta
1.0.0-beta.1 # Beta iteration 1
1.0.0-rc.1 # First release candidate
1.0.0-rc.2 # Second release candidate
1.0.0 # Final release!

Important: A pre-release version is always less than the normal version:

1.0.0-alpha < 1.0.0-beta < 1.0.0-rc.1 < 1.0.0

This means 1.0.0-rc.1 comes before 1.0.0 in sort order, which is what you want.

Build Metadata (Optional)​

Build metadata provides additional information about a specific build. It starts with a plus sign (+).

1.0.0+20241215
1.0.0+build.123
1.0.0-beta.1+sha.abc1234

Common metadata:

ExampleWhat It Contains
+20241215Build date
+build.123CI build number
+sha.abc1234Git commit hash
+20241215.abc1234Date and commit

Important: Build metadata is ignored when comparing versions:

1.0.0+build.1 == 1.0.0+build.999  # Same version!

This makes sense because both builds represent the same release, just built at different times or on different machines.

Putting It All Together​

Here are complete examples showing all parts:

VersionPrefixCorePre-releaseMetadata
1.0.0-1.0.0--
v1.0.0v1.0.0--
v2.1.3-alphav2.1.3alpha-
v1.0.0-rc.1v1.0.0rc.1-
1.0.0+build.456-1.0.0-build.456
v3.2.1-beta.2+20241215.abc1234v3.2.1beta.220241215.abc1234

Character Rules​

Version strings have specific rules about what characters are allowed:

In Core Version Numbers​

Only digits 0-9. No letters, no symbols.

1.2.3      ✓ Valid
1.2.3a ✗ Invalid (letter in patch)
1.2.3.4 ✗ Invalid for SemVer (too many parts)

In Pre-release and Metadata​

Allowed characters:

  • Digits: 0-9
  • Letters: a-z, A-Z
  • Hyphen: -
1.0.0-alpha       ✓ Valid
1.0.0-alpha.1 ✓ Valid
1.0.0-my-feature ✓ Valid (hyphens OK)
1.0.0-alpha_1 ✗ Invalid (underscore not allowed)
1.0.0-alpha 1 ✗ Invalid (space not allowed)

No Leading Zeros in Numbers​

Numeric identifiers cannot have leading zeros:

1.0.0-alpha.1    ✓ Valid
1.0.0-alpha.01 ✗ Invalid (leading zero)
1.0.0-alpha.0 ✓ Valid (just zero is fine)

Version Comparison (Sorting)​

When versions are sorted, they follow these rules:

1. Compare Core Numbers Left to Right​

1.0.0 < 2.0.0      # Major differs
1.1.0 < 1.2.0 # Minor differs
1.1.1 < 1.1.2 # Patch differs

2. Pre-release Comes Before Release​

1.0.0-alpha < 1.0.0
1.0.0-rc.99 < 1.0.0

3. Pre-release Identifiers Compare Left to Right​

1.0.0-alpha < 1.0.0-beta           # "alpha" < "beta" alphabetically
1.0.0-alpha.1 < 1.0.0-alpha.2 # 1 < 2 numerically
1.0.0-alpha < 1.0.0-alpha.1 # Shorter < longer

4. Numbers Compare as Numbers, Not Text​

1.0.0-alpha.2 < 1.0.0-alpha.10     # 2 < 10 (numeric comparison)

This is important! Text sorting would put 10 before 2, but version sorting correctly recognizes 10 > 2.

5. Build Metadata is Ignored​

1.0.0+build.1 == 1.0.0+build.999   # Same precedence

Complete Example: A Release Cycle​

Here's how versions might progress through a typical release:

0.1.0              # Initial development
0.2.0 # More features
0.9.0 # Getting close to 1.0
1.0.0-alpha # First 1.0 preview
1.0.0-alpha.1 # Alpha bugfix
1.0.0-alpha.2 # More alpha fixes
1.0.0-beta # Feature complete, testing
1.0.0-beta.1 # Beta bugfix
1.0.0-rc.1 # Release candidate
1.0.0-rc.2 # Fix last-minute issue
1.0.0 # Official release!
1.0.1 # Patch release (bugfix)
1.1.0 # Minor release (new feature)
2.0.0 # Major release (breaking changes)

Special Formats​

Go Module Versions​

Go requires a v prefix and has a special format for untagged commits called "pseudo-versions":

v1.2.3                                    # Normal version
v0.0.0-20241215103045-abc123def456 # Pseudo-version

The pseudo-version contains:

  • A base version (v0.0.0)
  • A timestamp (20241215103045 = 2024-12-15 10:30:45 UTC)
  • A commit hash prefix (abc123def456)

Dynamic Content in Versionator​

Versionator can generate version components dynamically using templates:

# .versionator.yaml
prerelease:
template: "alpha-{{CommitsSinceTag}}"
metadata:
template: "{{BuildDateTimeCompact}}.{{ShortHash}}"

This might produce: 1.0.0-alpha-5+20241215103045.abc1234

The {{...}} parts are replaced with actual values when you run versionator.

Quick Reference​

PartRequiredStarts WithAllowed CharactersExample
PrefixNo-v or V onlyv
MajorYes-digits1
MinorYes.digits.2
PatchYes.digits.3
Pre-releaseNo-digits, letters, -, .-beta.1
MetadataNo+digits, letters, -, .+build.456

See Also​