Semantic Versioning
Semantic Versioning (SemVer) is a versioning scheme that uses a three-part version number: MAJOR.MINOR.PATCH.
Version Format
MAJOR.MINOR.PATCH[-prerelease][+build-metadata]Examples:
1.0.0- Initial release1.2.3- Stable version2.0.0-alpha.1- Pre-release version1.5.0+build.123- With build metadata
When to Bump Versions
MAJOR Version (X.0.0)
Bump the major version when you make incompatible API changes.
Examples:
- Remove or rename a function
- Change function signatures
- Restructure data formats
- Remove dependencies that were part of the public API
MINOR Version (0.Y.0)
Bump the minor version when you add new functionality in a backwards-compatible manner.
Examples:
- Add new features
- Add new methods to classes
- Improve existing features
- Add deprecation warnings
PATCH Version (0.0.Z)
Bump the patch version when you make backwards-compatible bug fixes.
Examples:
- Fix bugs
- Fix performance issues
- Update dependencies for security fixes
- Fix documentation
Pre-release Versions
Pre-release versions are indicated by appending a hyphen and a series of dot-separated identifiers:
1.0.0-alpha
1.0.0-alpha.1
1.0.0-beta
1.0.0-beta.2
1.0.0-rc.1
2.0.0-previewPre-release versions:
- Indicate unstable versions
- Take precedence below the associated normal version
- Are useful for testing before official release
Examples of precedence:
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta
< 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11
< 1.0.0-rc.1 < 1.0.0Build Metadata
Build metadata is indicated by appending a plus sign and a series of dot-separated identifiers:
1.0.0+20130313144700
1.0.0+build.1
1.0.0+exp.sha.5114f85Build metadata:
- Should be ignored when determining version precedence
- Useful for tracking build information
Versu and Semantic Versioning
Versu automatically handles semantic versioning by:
- Analyzing commits using Conventional Commits
- Determining the highest version bump needed
- If any breaking change → MAJOR bump
- Else if any feature → MINOR bump
- Else if any fix → PATCH bump
- Applying that bump to the current version
- Optionally creating pre-release versions
Example Workflow
Starting with version 1.0.0:
Commits:
- feat: add new feature → Would bump to 1.1.0
- fix: resolve bug → Would bump to 1.0.1
Result: 1.1.0 (minor takes precedence)
Next cycle with version 1.1.0:
- feat(api)!: redesign API → Would bump to 2.0.0
- feat: add utility → Would bump to 1.2.0
Result: 2.0.0 (breaking change takes precedence)Configuration in Versu
Configure how Versu handles versioning:
# Enable pre-release versioning
versu run --prerelease-mode --prerelease-id alpha
# Add build metadata with short git hash
versu run --add-build-metadata
# Use timestamps prerelease identifiers
versu run --prerelease-mode --timestamp-versions
# Add SNAPSHOT suffix for development versions
# if supported by your plugins
versu run --append-snapshotIn addition, you can customize versioning rules and their effect on version bumps in your versu.config.js. The example below keeps the defaults for code changes but disables bumps for non-code types (by default, all recognized types trigger at least a patch bump):
export default {
versioning: {
breakingChange: {
stable: "major",
prerelease: "premajor",
},
unknownCommitType: {
stable: "patch",
prerelease: "prepatch",
},
commitTypes: {
feat: {
stable: "minor",
prerelease: "preminor",
},
fix: {
stable: "patch",
prerelease: "prepatch",
},
perf: {
stable: "patch",
prerelease: "prepatch",
},
refactor: {
stable: "patch",
prerelease: "prepatch",
},
docs: {
stable: "none",
prerelease: "none",
},
test: {
stable: "none",
prerelease: "none",
},
chore: {
stable: "none",
prerelease: "none",
},
style: {
stable: "none",
prerelease: "none",
},
ci: {
stable: "none",
prerelease: "none",
},
build: {
stable: "none",
prerelease: "none",
},
},
cascadeRules: {
stable: {
major: "major",
minor: "minor",
patch: "patch",
},
prerelease: {
premajor: "premajor",
preminor: "preminor",
prepatch: "prepatch",
prerelease: "prerelease",
},
},
},
}Best Practices
✅ Do's
- Use semantic versioning for public APIs
- Increment MAJOR for breaking changes
- Use pre-releases for testing
- Document breaking changes clearly
- Keep versions consistent across related packages
❌ Don'ts
- Skip version numbers
- Use 0.0.x indefinitely (stabilize to 1.0.0)
- Break API without incrementing MAJOR
- Commit breaking changes without pre-release testing
Relationship with Commits
Semantic Versioning defines what to increment, while Conventional Commits specifies how to determine what to increment:
feat:commits → MINOR version bumpfix:commits → PATCH version bumpBREAKING CHANGE:commits → MAJOR version bump
Further Reading
Ready to understand more? Check out Multi-Module Projects!
