Conventional Commits 1.0.0
Write commit messages following the Conventional Commits 1.0.0 specification so history is explicit and drives SemVer bumps, changelogs, and release automation.
When to Use
- Composing any commit message (
git commit). - Choosing the right type/scope for a change.
- Indicating a breaking change.
- Writing a multi-paragraph body or footers (e.g.
Refs:,Reviewed-by:). - Validating an existing message against the spec.
Format
<type>[optional scope][!]: <description>
[optional body]
[optional footer(s)]
- type: a noun such as
featorfix, followed by an optional scope, an optional!, then a REQUIRED colon and space. - description: a short summary, immediately after the
:. - body: optional; begins one blank line after the description; free-form paragraphs.
- footer(s): optional; begin one blank line after the body; each is
Token: valueorToken #value.
Procedure
- Pick the type that best matches the change (see table). If it fits more than one, make separate commits.
- Add a scope if it usefully names the affected area:
fix(driver): .... - Write the description: imperative mood, concise, lowercase, no trailing period.
- Mark breaking changes with
!before the colon and/or aBREAKING CHANGE:footer. - Add body/footers if context, reasoning, or references are needed.
- Commit, preferably passing the message via
-m(repeat-mfor body/footer paragraphs):git commit -m "feat(parser): add ability to parse arrays" # with body + footer: git commit -m "fix: prevent racing of requests" \ -m "Introduce a request id and a reference to the latest request." \ -m "Refs: #123"
Types (and SemVer mapping)
| Type | Use for | SemVer |
|---|---|---|
feat |
A new feature | MINOR |
fix |
A bug fix | PATCH |
docs |
Documentation only | — |
style |
Formatting/whitespace, no code-behavior change | — |
refactor |
Code change that neither fixes a bug nor adds a feature | — |
perf |
Performance improvement | — |
test |
Adding or fixing tests | — |
build |
Build system or external dependencies | — |
ci |
CI configuration and pipelines | — |
chore |
Other maintenance (tooling, housekeeping) | — |
revert |
Revert a previous commit | — |
any type with ! or BREAKING CHANGE: |
Backward-incompatible change | MAJOR |
Only feat and fix are mandated by the spec; the rest are the widely used Angular/commitlint set. Types other than feat/fix have no implicit SemVer effect unless they carry a breaking change. Teams MAY define additional types.
Breaking Changes
Indicate a breaking change in either place (or both):
- In the prefix: put
!immediately before the colon —feat!: ...orfeat(api)!: .... The description then describes the break, and the footer MAY be omitted. - In a footer:
BREAKING CHANGE: <description>. The token MUST be uppercase (BREAKING-CHANGEis an accepted synonym). A breaking change may accompany any type.
feat!: drop support for Node 6
BREAKING CHANGE: use JavaScript features not available in Node 6.
Scope
A scope is a noun in parentheses naming a section of the codebase: feat(lang): add Polish language, fix(parser): handle empty input. It is optional.
Body & Footers
- The body begins one blank line after the description and may span multiple paragraphs.
- Footers begin one blank line after the body. Each footer token uses
-instead of spaces (e.g.Reviewed-by,Acked-by,Refs), exceptBREAKING CHANGE. Separator is:or#. - A footer value may contain spaces and newlines; parsing ends at the next valid footer token.
fix: prevent racing of requests
Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.
Reviewed-by: Z
Refs: #123
Reverts
The spec does not mandate revert behavior. Recommended form: the revert type with a footer referencing the reverted commit SHAs.
revert: let us never again speak of the noodle incident
Refs: 676104e, a215868
Casing
Units of a Conventional Commit are case-insensitive, except BREAKING CHANGE, which MUST be uppercase. Pick one casing for types and be consistent (this repo uses lowercase, e.g. fix:, ci:).
Examples
| Message | Valid | Note |
|---|---|---|
docs: correct spelling of CHANGELOG |
✅ | No body |
feat(lang): add Polish language |
✅ | Scope |
feat: allow config object to extend other configs |
✅ | With BREAKING CHANGE: footer |
feat(api)!: send email when a product is shipped |
✅ | Scope + ! breaking |
revert: let us never again speak of the noodle incident |
✅ | Revert with Refs: footer |
fix: array parsing issue when multiple spaces in string |
✅ | Imperative description |
feat:missing space after colon |
❌ | Colon MUST be followed by a space |
Fixed the parser bug |
❌ | No type prefix |
feat(parser) add arrays |
❌ | Missing colon |
feat: breaking change (real break, no !/footer) |
❌ | Breaking change not indicated |
Why It Matters
Conventional Commits enable automatic CHANGELOG generation, automatic SemVer bump detection (fix→PATCH, feat→MINOR, breaking→MAJOR), clearer history, and triggering of build/publish pipelines. It pairs with the conventional-branch (branch names) and semantic-versioning (release versions) skills.