Conventional Commits is a specification for commit message format (conventionalcommits.org, grew out of the Angular commit convention, public 1.0.0 in 2018). Do not confuse it with Tim Pope's "50/72 + imperative mood" style: that one covers line length and tone, not the structured prefix. A type prefix on the subject line makes history machine-readable: changelog and semver bumps can be generated automatically.
Format
<type>(<scope>): <subject>
[optional body]
[optional footer]
- type is required. The category of the change.
- scope is optional. The module or subsystem.
- subject is a short description in imperative mood, at most 50 characters including the prefix.
- body gives details, wrapped at 72 columns.
- footer holds ticket references,
BREAKING CHANGE:,Co-authored-by:.
Types
feat: new user-facing featurefix: bug fixdocs: documentation onlystyle: formatting, whitespacerefactor: code change with no new feature and no bug fixperf: performance improvementtest: adding or correcting testschore: maintenance (deps, configs)build,ci: build infrastructurerevert: undoing another commit
The list is open. Teams add their own (security, i18n). Document
whatever you add in the project's contributing guide.
Examples
feat(auth): add password reset flow
fix(api): handle null in user.profile
docs(readme): document SSL setup
chore(deps): bump react to 18.3.1
refactor!: drop support for Node 16
Breaking changes
Two ways to mark them:
1. ! after the type:
refactor(api)!: rename POST /user to POST /users
2. BREAKING CHANGE: in the footer:
feat(api): rename POST /user to POST /users
BREAKING CHANGE: endpoint /user no longer exists,
use plural /users.
You can combine both: ! for brevity, BREAKING CHANGE: for a detailed
migration explanation.
Why use it
Two main reasons:
- Automatic changelog. Tools such as
standard-version,release-please, andsemantic-releaseparse the history, group entries by type, and generate CHANGELOG.md. - Automatic semver.
fix:→ patch,feat:→ minor,BREAKING CHANGE:→ major. The connection to semver.
Without an automated release process, the format adds only team discussion overhead. If you maintain the CHANGELOG by hand, you can skip the prefixes with no ill effects.
Pitfalls
- Do not confuse
styleandfeat.style: reformat codemeans whitespace and indentation only.feat: change button colorsis a visible user change, even if it is technically only CSS. scopeis not required. For a small project you can omit it. For a large one it is practically required; without it the history becomes unreadable.- The
commitlintpre-commit hook checks the format and blocks a non-conforming commit. Useful as a safety net.