How to Use Conventional Commits for API Versioning

How to use conventional commits to write clear Git messages, automate changelogs, and manage semantic versioning with standard types like feat and fix.

Jump to section

Jump to section

Jump to section

Conventional commits transform your Git history from a collection of random messages into a structured, machine-readable record of API changes. This standardized format enables automated versioning, changelog generation, and SDK releases across multiple languages—turning what used to be manual, error-prone processes into reliable automation.

This guide covers how to structure conventional commits for APIs, which commit types trigger version bumps, and how platforms like Stainless use this commit history to automatically generate and release SDKs whenever you update your OpenAPI specification.

What are conventional commits for API versioning

Conventional commits are a standardized format for your Git commit messages. For APIs, this format is more than just a good habit for readability; it creates a machine-readable history of changes. This allows tools to automatically determine if a change requires a major, minor, or patch version bump, which is the foundation of semantic versioning and release automation.

An ad-hoc commit like update users tells you very little. In contrast, a conventional commit like feat(users): add email verification endpoint is explicit. It tells you the type of change, the part of the API affected, and a clear summary of what happened.

This simple discipline is the key to automating your entire release process. By structuring your commits this way, you can automatically generate changelogs and, with a platform like Stainless, trigger new versioned SDK releases across every language you support.

How to structure conventional commits for APIs

The structure of a conventional commit is designed to be simple for humans to write and easy for machines to parse. Every part of the commit message has a specific purpose that maps directly to the lifecycle of an API change.

Essential commit format

The full format follows this pattern: <type>(<scope>): <description>. An optional body can provide more context, and an optional footer is used to signal breaking changes.

  • Type: A short keyword like feat for a new feature or fix for a bug fix that signals the nature of the change.

  • Scope: The section of the API that was changed. This is optional but highly recommended for APIs.

  • Description: A brief, imperative summary of the change, written in the present tense.

  • Body: A longer, more detailed explanation of the change, explaining the "what" and "why".

  • Footer: Used for metadata, most importantly to declare a BREAKING CHANGE:.

API-specific scopes

For APIs, the scope is your best friend for creating clear, organized changelogs. A good practice is to use the name of the API resource you're changing as the scope.

  • feat(payments): add support for 3D Secure

  • fix(auth): resolve issue with token refresh logic

  • docs(webhooks): clarify signature verification process

When your changelog is automatically generated, these scopes group related changes together. This makes it easy for your users to see what has changed in the parts of the API they care about.

Which commit types trigger API version changes

The type field in your commit message is the primary signal for automated versioning tools. It directly controls whether your API's version number gets a major, minor, or patch increment, following the rules of semantic versioning.

Commit Type

Example

Version Bump

Description

feat

feat(users): add profile picture upload

Minor (e.g., 1.2.5 → 1.3.0)

A new, backward-compatible feature is added to the API.

fix

fix(orders): correct tax calculation for EU

Patch (e.g., 1.2.5 → 1.2.6)

A backward-compatible bug fix is made.

BREAKING CHANGE

feat(auth)!: replace API keys with OAuth2

Major (e.g., 1.2.5 → 2.0.0)

A change that is not backward-compatible.

Major version changes

A major version change signals a backward-incompatible update that will likely require your users to change their code. You can trigger this in two ways.

  1. Append a ! to the type/scope: feat(auth)!: switch to OAuth2

  2. Add a BREAKING CHANGE: footer to the commit body.

An example of a breaking API change is removing an endpoint, changing a required parameter, or significantly altering the structure of a response object. When a platform like Stainless detects a breaking change, it will only increment the major version if your SDK is already at version 1.0.0 or higher, preventing premature major bumps during initial development.

Minor version changes

A feat commit triggers a minor version bump. This indicates that you've added new functionality in a way that is backward-compatible.

  • Adding a new, optional field to a JSON response.

  • Introducing a completely new API endpoint.

  • Adding an optional query parameter to an existing endpoint.

Your users can safely upgrade to a new minor version without their existing integrations breaking.

Patch version changes

A fix commit triggers a patch version bump. This is for backward-compatible bug fixes that correct incorrect behavior without adding new features. Other types like docs, chore, refactor, and perf also typically result in a patch release if they affect the generated code, as they don't change the public API contract.

  • Fixing a typo in an error message description.

  • Correcting a calculation that was producing the wrong output.

  • Improving documentation for an endpoint.

How to write commits for API changes

Let's walk through a practical example. Imagine you're adding a new, optional status filter to your /tasks endpoint. Your change in the OpenAPI spec adds the parameter.

Your commit message should be: feat(tasks): add optional status filter to list endpoint.

This is simple and effective. Now, consider a more complex change where you are deprecating an old field in favor of a new one.



This commit clearly communicates the feature, the rationale, and the breaking change, providing everything needed for an automated tool to generate a perfect changelog entry and bump the version to 2.0.0.

How conventional commits automate SDK releases

The real power of conventional commits is unlocked when you connect them to an automated release pipeline. After all, your API isn't finished until the SDK ships, and automation ensures this happens consistently.

Commit–semantic versioning link

An automated release tool reads your commit history since the last release. It analyzes the commit types to calculate the correct next version.

  • History: fix(auth): ..., docs(billing): ..., feat(webhooks): ...

  • Analysis: The tool sees a feat commit, which is the highest-impact change.

  • Result: If the current version is 1.3.2, the next version will be 1.4.0.

The tool then generates a CHANGELOG.md file, grouping commits by their type, creating a human-readable summary of what's new.

Stainless and OpenAPI automation

This automation becomes even more powerful when tied to your OpenAPI spec. If you don't have one yet, you'll need to create OpenAPI specs for your API first. With a platform like Stainless, the workflow is seamless.

  1. You push an updated OpenAPI spec to your repository with a conventional commit message.

  2. A GitHub Action triggers a build, sending the spec and commit message to Stainless. Teams often test OpenAPI changes on development branches before merging to main.

  3. Stainless regenerates your SDKs in TypeScript, Python, Go, Java, and any other language you've configured, preserving any custom code you've added.

  4. It then opens a "Release PR" in your GitHub repo containing the new SDK code, a generated changelog, and the correctly bumped version number.

  5. Once you review and merge the PR, the new SDK packages are automatically published to their respective registries like npm and PyPI.

How to handle breaking changes in APIs

Breaking changes are inevitable in a growing API, but they must be managed carefully to avoid disrupting your users. Conventional commits are a key part of a safe deprecation strategy.

Here is a simple checklist for managing breaking changes:

  1. Introduce the new: Add the new endpoint or field while keeping the old one functional.

  2. Mark as deprecated: Update your OpenAPI spec and documentation to mark the old functionality as deprecated, and integrate SDK snippets to show migration examples.

  3. Communicate: Announce the deprecation and provide a clear timeline for its removal.

  4. Remove: After a reasonable grace period, remove the old functionality in a commit clearly marked as a BREAKING CHANGE.

Your BREAKING CHANGE: footer should be a mini-migration guide, giving users a clear path forward.

BREAKING CHANGE: The /v1/charges endpoint has been removed. Please use the /v1/payment_intents endpoint instead. See our migration guide at docs.yourapi.com/migrations/payment-intents.

This ensures the change is not only technically flagged for a major version bump but also clearly explained to your human users in the changelog.

Frequently asked questions about conventional commits for APIs

What is the 50/72 rule for commit messages?

This is a classic Git guideline suggesting the commit subject line be 50 characters or less, with body lines wrapped at 72 characters. Modern UIs make it less of a strict requirement, but brevity and clarity are still good principles.

Can I customize commit types for my API workflow?

Yes, you can configure tools like commitlint to recognize custom types. As long as you stick to the standard feat and fix for version-relevant changes, you can add other types for internal processes without affecting automated versioning.

How do I enforce conventional commits across my team?

Use pre-commit hooks with tools like husky and commitlint to check messages before they are committed locally. You can also add a CI check that fails pull requests if their commit messages don't follow the convention.

Do I need to rewrite my history before 1.0.0?

No, it's not necessary. The convention is most valuable once your API is public. Before your first public release, the API is considered unstable, and a less formal commit history is acceptable.

How do breaking changes in commits affect SDK consumers?

A commit with a BREAKING CHANGE: will trigger a major version bump in your SDK, from 1.5.2 to 2.0.0 for example. This is a critical signal to your users that the new version is not a drop-in replacement and they must read the changelog before upgrading.

Ready to automate your SDK releases? Get started for free.