Ctrl + K
Git19 min read

Semantic Versioning Workflow

A practical guide to using Semantic Versioning in a Git-based development workflow, from choosing version numbers to creating tags, changelogs, release notes, and automated releases.

Published: 2026-10-05

Semantic Versioning, commonly abbreviated as SemVer, provides a predictable way to communicate changes through software version numbers. Instead of treating a version such as 2.4.1 as an arbitrary sequence of numbers, a Semantic Versioning workflow gives each part of the version a defined meaning.

A good versioning workflow connects code changes, Git commits, releases, changelogs, package versions, and deployment processes. The goal is not simply to change a number before every release, but to make the release history understandable and predictable.

This guide explains how to build a practical Semantic Versioning workflow around Git, including when to increment MAJOR, MINOR, and PATCH versions, how to create Git tags, how to generate changelogs and release notes, and how to automate the process.

What Is Semantic Versioning?

Semantic Versioning is a convention for assigning version numbers to software releases. A standard SemVer version has three main components: MAJOR.MINOR.PATCH.

MAJOR.MINOR.PATCH

2.4.1

Each component communicates a different type of change. In a compatible software API, a MAJOR increment indicates incompatible changes, a MINOR increment indicates backward-compatible functionality, and a PATCH increment indicates backward-compatible bug fixes.

ComponentTypical meaningExample
MAJORIncompatible or breaking API changes2.4.1 → 3.0.0
MINORBackward-compatible new functionality2.4.1 → 2.5.0
PATCHBackward-compatible bug fixes2.4.1 → 2.4.2

Semantic Versioning is especially useful for libraries and APIs because consumers can use the version number as an indication of compatibility. For applications, teams can also use SemVer as a release-management convention even when users do not directly consume the application as a dependency.

Why Use a Semantic Versioning Workflow?

Changing version numbers manually without a defined process often leads to inconsistent releases. One developer may consider a feature a minor release while another may classify the same change as a patch.

  • Make release versions predictable.
  • Communicate the type of change through the version number.
  • Connect releases to Git history.
  • Make package versions easier to manage.
  • Generate consistent changelogs and release notes.
  • Make dependency compatibility easier to reason about.
  • Automate repetitive release tasks.
  • Provide a clear release history for users and developers.

The Core Semantic Versioning Workflow

A practical workflow can be organized into a small number of repeatable steps: develop changes, classify the changes, determine the next version, update release metadata, create a Git tag, generate release documentation, and publish the release.

  • Develop and review changes.
  • Merge the intended changes into the release branch or main branch.
  • Determine whether the release is MAJOR, MINOR, or PATCH.
  • Calculate the next version.
  • Update package or application version metadata.
  • Generate or update the changelog.
  • Create a Git tag for the release.
  • Create release notes.
  • Publish the package or application.
  • Verify the released version.

The exact order can vary depending on the project and automation system. What matters is that the process is repeatable and the Git tag, package version, changelog, and release artifacts do not accidentally describe different versions.

Step 1: Develop and Review Changes

Versioning should happen after the actual changes have been reviewed. A release version should describe a coherent set of changes rather than an arbitrary point in development.

For example, a release might contain several bug fixes and documentation improvements. If there is no new public functionality and no breaking API change, the resulting release may be a PATCH release.

Keeping commits focused and using pull requests or another review process makes it easier to determine what actually changed between releases.

Step 2: Classify the Changes

Before selecting a version number, review the changes since the previous release. Ask three basic questions:

  • Did the release introduce an incompatible change?
  • Did it add backward-compatible functionality?
  • Did it only fix bugs or make other backward-compatible corrections?

If multiple types of changes are present, the highest-impact applicable version increment determines the release. A release containing both a new feature and a breaking API change requires a MAJOR increment because the breaking change affects compatibility.

When to Increment MAJOR

A MAJOR version is used when incompatible changes are introduced. The exact definition of breaking depends on the public API and compatibility contract of the project.

3.2.4 → 4.0.0

Examples can include removing a public API, changing an API in an incompatible way, changing required parameters, or altering documented behavior in a way that requires consumers to change their code.

ChangePossible classification
Remove a public functionMAJOR
Rename a required API fieldMAJOR
Change a public interface incompatiblyMAJOR
Change behavior that consumers rely on in an incompatible wayMAJOR
⚠️ Do not classify a change as PATCH simply because it is small in terms of code size. Versioning is about compatibility and public behavior, not the number of changed lines.

When to Increment MINOR

A MINOR release adds backward-compatible functionality to a stable major version.

3.2.4 → 3.3.0

Examples include adding a new optional API feature, introducing a new public function without removing existing behavior, or adding functionality that existing consumers can continue to use without modification.

When to Increment PATCH

A PATCH release is generally used for backward-compatible bug fixes.

3.2.4 → 3.2.5

Typical examples include correcting incorrect calculations, fixing crashes, resolving compatibility bugs, or correcting implementation details without changing the public API incompatibly.

Choosing the Next Version

Once the changes have been classified, select the next version from the current version. Only one of the three main components is normally incremented for a standard release, with lower components reset when a higher component changes.

CurrentChange typeNext version
1.4.2Bug fix1.4.3
1.4.2New compatible feature1.5.0
1.4.2Breaking change2.0.0
2.7.9Bug fix2.7.10
2.7.9New compatible feature2.8.0
2.7.9Breaking change3.0.0

Automating Version Calculation

The arithmetic involved in Semantic Versioning is simple, but automation helps eliminate manual mistakes. A version calculator can take the current version and the type of release and produce the next version.

Current version: 2.4.1
Release type: minor
Next version: 2.5.0

This is particularly useful in CI/CD pipelines where the version must be calculated consistently from release metadata or commit information.

Version Comparison

A Semantic Versioning workflow also needs a consistent way to compare versions. Numeric comparison of the complete version string is incorrect in many cases.

2.10.0
2.9.0

SemVer compares numeric version components rather than treating the entire version as a decimal number. Therefore, 2.10.0 is a later version than 2.9.0.

A Semantic Version comparator can be useful when checking whether a dependency or release satisfies a required version range.

Step 3: Update the Project Version

Once the next version has been determined, update the version wherever the project uses it as release metadata. The exact location depends on the ecosystem.

{
  "name": "example-package",
  "version": "2.5.0"
}

For npm packages, the version is normally stored in package.json. Other ecosystems may use different files or build metadata.

Using npm Version Commands

npm provides commands for changing package versions. For example:

npm version patch
npm version minor
npm version major

These commands can update the package version and, depending on configuration and workflow, create a Git commit and tag. Teams should understand exactly what their package manager command changes before incorporating it into automated release scripts.

💡 Use one authoritative versioning process. Avoid manually changing package.json, Git tags, and release metadata independently if your tooling can keep them synchronized.

Step 4: Update the Changelog

A changelog records meaningful changes between releases. While the version number communicates the general compatibility impact, the changelog explains what actually changed.

## 2.5.0

### Added

- Added support for configurable request timeouts.
- Added a new API for retry configuration.

### Fixed

- Fixed incorrect handling of empty responses.

A good changelog should focus on changes that matter to users, developers, operators, or package consumers. It does not need to contain every internal commit.

Keep Changelog Entries Useful

  • Describe user-visible changes.
  • Mention breaking changes clearly.
  • Group related changes logically.
  • Avoid meaningless internal commit messages.
  • Include migration information when necessary.
  • Keep wording concise and consistent.

Automating Changelogs

Changelog generation can be automated when commits or pull requests follow a consistent structure. Conventional Commits are one common approach because commit types provide machine-readable information about changes.

feat: add request timeout configuration
fix: handle empty API responses
docs: improve installation guide

A release process can use this information to group changes into categories such as features, fixes, and documentation updates. Automation should still be reviewed before publishing release notes because commit messages are not always written for end users.

Step 5: Create a Git Tag

Git tags associate a name with a specific commit. Release tags are useful because they provide a stable reference to the source state used for a release.

git tag v2.5.0
git push origin v2.5.0

The v prefix is a widespread convention for release tags, although Semantic Versioning itself describes the version number rather than requiring a particular Git tag format.

Annotated Git Tags

For release management, annotated tags can provide additional metadata and a release message.

git tag -a v2.5.0 -m "Release v2.5.0"
git push origin v2.5.0

A project should choose one tagging convention and use it consistently.

Step 6: Create Release Notes

Release notes are usually more user-oriented than a raw Git log. They explain the important changes in a particular release and can include upgrade instructions, breaking changes, known issues, and links to documentation.

# Release 2.5.0

## Highlights

Added configurable request timeouts.

## Changes

- Added timeout configuration.
- Added retry options.
- Fixed empty-response handling.

## Upgrade notes

Existing configurations remain compatible.

Release notes can be generated from commits, pull requests, or changelog entries, but they should be reviewed for clarity before publication.

Changelog vs Release Notes

These terms are related but can serve different purposes. A changelog is typically a persistent historical record across many versions, while release notes focus on communicating the contents of a particular release.

ChangelogRelease notes
Maintains a long-term release history.Focuses on one release.
Usually concise and structured.Can provide more context.
Useful for browsing versions.Useful for announcing an update.
Often generated or maintained continuously.Usually published with a release.

Step 7: Publish the Release

The final publication step depends on the project. A library may be published to a package registry, while an application may produce a container image, installer, binary, or deployment artifact.

The release artifact should correspond to the same version represented by the Git tag and project metadata.

Git tag:       v2.5.0
Package:       2.5.0
Release notes: 2.5.0
Artifact:      2.5.0

Keeping these identifiers synchronized makes it much easier to determine exactly what code was released.

Pre-Releases in a Semantic Versioning Workflow

Semantic Versioning also supports pre-release identifiers. They are useful when a version is available for testing before the final release.

2.5.0-alpha.1
2.5.0-beta.1
2.5.0-rc.1
2.5.0

Common labels include alpha, beta, and release candidate, although the exact naming convention can be chosen by the project.

When to Use Pre-Releases

  • Testing a major redesign before a stable release.
  • Allowing selected users to test a new feature.
  • Validating compatibility with other software.
  • Testing release candidates before final publication.
  • Publishing experimental package versions without marking them as stable.

Build Metadata

Semantic Versioning also supports build metadata after a plus sign.

2.5.0+build.184

Build metadata can identify build information without changing the precedence of the underlying SemVer version. Projects should use it consistently if build metadata is included in their release identifiers.

Managing Breaking Changes

Breaking changes deserve special treatment because the MAJOR version communicates that existing consumers may need to modify their code or configuration.

  • Document the breaking change clearly.
  • Explain what consumers need to change.
  • Provide migration instructions when practical.
  • Mention removed or renamed APIs.
  • Update examples and documentation.
  • Test the migration path before release.
## Breaking changes

- The legacy timeout option has been removed.
- Replace `timeout` with `requestTimeout`.
- Update configuration before upgrading to version 3.0.0.

Semantic Versioning for APIs

Semantic Versioning is particularly useful for public APIs because consumers often need to know whether an update can be adopted without code changes.

API changeTypical SemVer treatment
Add an optional response fieldMINOR
Add a new endpoint without changing existing endpointsMINOR
Fix an incorrect responsePATCH, assuming compatibility is preserved
Remove an endpointMAJOR
Rename a required request fieldMAJOR

API compatibility must be evaluated according to the API's documented contract. A change that appears small internally can still be breaking for consumers.

Semantic Versioning for npm Packages

For npm packages, the package version is part of the package metadata and is used by package managers when resolving dependencies. A consistent SemVer workflow helps package consumers understand the scope of updates.

{
  "name": "example-library",
  "version": "3.2.0"
}

When publishing a new package version, make sure the version in package metadata, Git history, release tag, changelog, and published artifact all agree.

Dependency Version Ranges

Package ecosystems often use version ranges to express which dependency versions are acceptable. This makes correct Semantic Versioning especially important because dependency tools rely on version semantics when determining compatible updates.

{
  "dependencies": {
    "example-library": "^3.2.0"
  }
}

The exact meaning of a range depends on the package manager and versioning rules. Teams should understand the range syntax they use rather than assuming every dependency declaration behaves identically.

Automating Releases with CI/CD

A mature Semantic Versioning workflow can move much of the repetitive release process into CI/CD. A release pipeline can calculate the next version, update metadata, generate documentation, create a Git tag, publish artifacts, and create a release.

The exact implementation depends on the CI/CD platform and project ecosystem, but the conceptual workflow remains the same.

Review changes
Determine release type
Calculate version
Update version metadata
Generate changelog
Run tests
Create Git tag
Build artifact
Publish release

Run Tests Before Tagging

The release tag should identify a commit that has passed the project's required validation. Running tests before creating the final release tag reduces the chance of associating a published version with an invalid build.

  • Run unit tests.
  • Run integration tests where applicable.
  • Run linting and type checks.
  • Build the release artifact.
  • Validate package metadata.
  • Check generated changelog or release notes.
  • Verify the intended commit is being tagged.

Keep Release Artifacts Reproducible

A useful release process should make it possible to identify the source code and configuration used to produce an artifact. Git tags provide an important reference point, while locked dependencies and reproducible build practices can further improve consistency.

If the same version can unexpectedly produce substantially different artifacts, the version number loses some of its value as a release identifier.

Versioning Monorepos

Monorepositories introduce an additional question: should all packages share one version or should each package be versioned independently?

StrategyDescription
Fixed versioningMultiple packages share the same release version.
Independent versioningEach package receives its own version based on its changes.

Fixed versioning can simplify coordinated releases, while independent versioning can make package-level releases more precise. The right approach depends on how tightly the packages are coupled.

Handling Multiple Changes in One Release

A release can contain many changes. For example, a single MINOR release may contain several new features and bug fixes.

2.6.0

Added:
- Feature A
- Feature B

Fixed:
- Bug A
- Bug B

You do not normally increment the version separately for every commit. The version describes the resulting release as a whole.

Versioning Hotfixes

A hotfix is often released as a PATCH version when it contains a backward-compatible correction to a previously released version.

2.6.0 → 2.6.1

Teams that maintain multiple supported release lines may need a more complex branch and backporting strategy. In that case, the release workflow should clearly document which branch receives the fix and which versions are affected.

Release Branches and Semantic Versioning

Semantic Versioning does not require a particular Git branching strategy. A project can release directly from main, use release branches, or use another workflow.

The important requirement is that the selected Git workflow consistently identifies the source commit associated with each release.

Common Semantic Versioning Workflow Mistakes

  • Incrementing versions based on the number of changed files.
  • Calling a breaking API change a PATCH release.
  • Forgetting to reset MINOR and PATCH when incrementing MAJOR.
  • Forgetting to reset PATCH when incrementing MINOR.
  • Using inconsistent Git tag formats.
  • Updating package.json but forgetting the release tag.
  • Creating a tag before tests finish.
  • Generating release notes directly from meaningless commit messages.
  • Publishing a release without documenting breaking changes.
  • Manually changing version identifiers in several unrelated places.
  • Treating pre-release versions as ordinary stable releases.
  • Assuming every small code change should produce a PATCH release.

A Recommended Release Checklist

  • Review all changes since the previous release.
  • Identify breaking changes.
  • Identify new backward-compatible features.
  • Identify bug fixes.
  • Determine the appropriate release type.
  • Calculate the next Semantic Version.
  • Update package or application version metadata.
  • Run tests and quality checks.
  • Update the changelog.
  • Review release notes.
  • Create the release Git tag.
  • Build the release artifact.
  • Publish the artifact.
  • Verify the published version.

Example End-to-End Workflow

Suppose the current version is 1.8.3. During development, the team adds a new optional API feature and fixes two bugs. No existing API behavior is removed or made incompatible.

Because the release introduces backward-compatible functionality, it is classified as a MINOR release. The next version is therefore 1.9.0.

Current version: 1.8.3
New functionality: yes
Breaking changes: no
Bug fixes: yes

Next version: 1.9.0

The project version is updated to 1.9.0, tests are executed, the changelog is prepared, and a Git tag such as v1.9.0 is created on the release commit.

git tag -a v1.9.0 -m "Release v1.9.0"
git push origin v1.9.0

The release notes can then summarize the new feature and bug fixes. The package or application artifact is published using version 1.9.0.

How to Improve a Manual Release Workflow

A manual process is a reasonable starting point for a small project. As the number of releases grows, repetitive steps become good candidates for automation.

  • Standardize the Git tag format.
  • Keep the version in one authoritative source when possible.
  • Use conventional commit or pull request conventions if release automation benefits from them.
  • Automate version calculation.
  • Automate changelog generation.
  • Run tests automatically before publishing.
  • Generate release notes from structured change information.
  • Use CI/CD to build and publish artifacts.
  • Require review for production releases.

Semantic Versioning Tools

Several types of tools can simplify a Semantic Versioning workflow. Version calculators can determine the next MAJOR, MINOR, or PATCH release, while version comparators can check the ordering and compatibility of versions. npm version calculators are useful for package-specific workflows, and changelog or release-notes generators can turn structured change information into release documentation.

Frequently Asked Questions

What is a Semantic Versioning workflow?

It is a repeatable process for deciding release versions, updating project metadata, creating Git tags, documenting changes, and publishing software according to Semantic Versioning rules.

When should I increment the MAJOR version?

Increment MAJOR when the release introduces an incompatible change to the software's public API or compatibility contract.

When should I increment the MINOR version?

Increment MINOR when backward-compatible functionality is added to the current major version.

When should I increment the PATCH version?

Increment PATCH for backward-compatible bug fixes and similar corrections that do not introduce new public functionality or breaking changes.

Do Git tags have to use the v prefix?

No. Semantic Versioning does not require a particular Git tag format. A v prefix, such as v2.5.0, is a common convention, but the important part is consistency.

Should changelog generation be automated?

It can be. Automation works particularly well when commits or pull requests follow a consistent structure. Generated changelogs should still be reviewed before publication.

Can Semantic Versioning be used for applications instead of libraries?

Yes. Although SemVer is especially valuable for libraries and APIs, applications can also use it as a predictable release numbering convention.

Conclusion

A Semantic Versioning workflow turns version numbers into useful release information. Instead of choosing numbers arbitrarily, the team evaluates compatibility, new functionality, and bug fixes to determine whether the next release should be MAJOR, MINOR, or PATCH.

The most useful workflow connects this decision with Git tags, package metadata, tests, changelogs, release notes, and published artifacts. For small projects, these steps can be performed manually. As the project grows, version calculation, changelog generation, testing, tagging, and publishing can be automated through CI/CD.

The result is a release history that is easier to understand and maintain. Developers can identify what changed, package consumers can reason about compatibility, and teams can trace a published version back to a specific state of the source code.

Found an issue?

Found an error, outdated information, or something missing from this article? Let me know through the Contact page.

Your feedback helps improve our articles and keep them accurate and useful.