Conventional Commits Helper
Compose a spec-correct Conventional Commits message from a form — or paste one and lint it with commitlint-compatible checks.
Checks 9 commitlint-compatible rules from config-conventional.
Paste a message above — findings appear here.
Press ? for shortcuts
Do it offline:$ git commit -m "feat(api): add rate limiting"
How to use it
- Choose one of the eleven types in the Compose tab — feat and fix are the two the specification itself defines; the select explains the other nine in a few words each.
- Fill in the description, and optionally a scope, a body and footers. The message card updates as you type, with a header-length meter against the 100-character rule.
- Tick the breaking-change box to add ! after the type, and use a BREAKING CHANGE footer when you want the explanation in the message itself — the spec allows either marker, or both at once.
- To check a message you already have, open the Lint tab and paste it. Findings list a severity, a position and a commitlint-compatible rule id; a clean paste says so explicitly.
Pick a type, add an optional scope, write the description — this page assembles the exact Conventional Commits v1.0.0 message, blank lines and BREAKING CHANGE footer included. Or switch to the Lint tab and paste an existing message: it is checked against nine commitlint-compatible rules from config-conventional, each finding anchored to its line and column. Everything runs on this device; nothing you type is sent anywhere.
How it works
A Conventional Commits message has a fixed shape: a header written as type, optional (scope), optional !, then a colon, a space and the description; a free-form body one blank line below; and a footer block one blank line after the body. Footer tokens are single words that use hyphens in place of spaces, with BREAKING CHANGE as the one sanctioned exception, and a footer value keeps running until the next line that starts a new footer — so multi-line values are legal. The composer here builds that structure directly from the form fields and refuses anything the header grammar cannot carry, like parentheses inside a scope or a line break in the description.
The Lint tab implements nine rules under their commitlint-compatible ids, with the severities config-conventional assigns: type-enum, type-case, type-empty, scope-case, subject-empty, subject-full-stop and header-max-length report as errors, while body-leading-blank and footer-leading-blank report as warnings. The 100-character header rule is a finding, never a refusal — the tool still shows you the message so you can shorten it. Rule ids match the commitlint documentation so a finding here reads the same as one from a CI pipeline, but the checks are this page's own implementation running in your browser.
Formatting is held to a round-trip standard: the composed message must parse, and any header or footer field that could not survive the trip back — a line break in the description, a blank line inside a footer value — is refused rather than silently mangled, which is why the writer is stricter than the reader. One reading is deliberately lenient: a final body line shaped like a footer, say Fixes #42, is written byte-for-byte and reads back as a footer, because that is how any Conventional Commits reader classifies such a line. The project's test suite goes one step further — each example below is rebuilt from its form fields by the same engine this page runs, then committed with git commit -F inside a throwaway repository, so every message you see here has been accepted by real git, not just proofread.
Examples
type feat · scope api · description add rate limitingfeat(api): add rate limitingA scoped feature in its smallest legal form. The scope names the affected area of the codebase and always sits in parentheses between the type and the colon.
type fix · breaking change · footer BREAKING CHANGE: unknown keys in the config file now fail startup instead of being ignoredfix!: reject unknown config keys
BREAKING CHANGE: unknown keys in the config file now fail startup instead of being ignoredThe dual-marker case straight from the specification: ! flags the break in the header while the footer carries the explanation. Tools that only scan headers and tools that only read footers both see it.
type revert · description let us never again speak of the noodle incident · footer Refs: 676104e, a215868revert: let us never again speak of the noodle incident
Refs: 676104e, a215868The revert idiom the spec's own FAQ recommends: a revert type plus a Refs footer listing the SHAs of the commits being rolled back.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
! and the BREAKING CHANGE footer are interchangeable
The specification treats a ! in the header and a BREAKING CHANGE footer as equivalent ways to declare a breaking change, and explicitly permits using both in one commit. If you use only the !, the description is assumed to explain the break; the footer form exists for when you want a longer explanation that changelog generators can lift out verbatim.
BREAKING CHANGE must be uppercase; BREAKING-CHANGE is its synonym
Item 15 of the spec makes everything case-insensitive except this one token, and item 16 requires tools to accept the hyphenated spelling too. A footer written as Breaking Change: is therefore refused by the Compose tab rather than silently kept — a changelog tool scanning for the uppercase token would walk right past it. The Lint tab stays quiet about it by design: the nine config-conventional rules include no breaking-token case check, so a default commitlint setup would not flag it either.
Merge and fixup commits sit outside the spec
Lines like Merge branch 'main' or fixup! earlier subject are produced by git itself and by autosquash workflows; they are not Conventional Commits headers, and pasting one into the Lint tab fails the type rules by design. Teams typically let merge commits through untouched and squash fixups away before any commit-message check runs.
Lowercase types: a config-conventional law, not a spec law
The specification says types are case-insensitive, so FIX: would be spec-legal. The config-conventional ruleset most projects adopt pins type-case and scope-case to lower-case anyway, and its type-enum list is lowercase, so the Lint tab reports uppercase types against both rules — matching what a default commitlint setup rejects, and said here honestly as the stricter of the two sources.
Two footer separators parse, one is written
A footer may separate token from value with a colon and space or with a space and #, so Fixes #42 is a legal footer whose token is Fixes. When this page rebuilds a message it always writes the colon form, keeping the # with the value so no character of the reference is dropped.
Common errors
The header's colon must be followed by one space — "type: description" (Conventional Commits v1.0.0 §1).- feat:add thing fails because the space after the colon is part of the required separator, not styling. Insert one space after the colon and the header parses.
The description is empty — text after the colon and space is required (Conventional Commits v1.0.0 §5).- A header like feat: with nothing after it has a type but no description, and the description is mandatory. Write what the change does in the imperative and keep the whole header inside the length rule.
"Breaking Change" must be uppercase — write "BREAKING CHANGE:" or "BREAKING-CHANGE:" (Conventional Commits v1.0.0 §15–§16).- The one case-sensitive token in the entire grammar. Mixed-case variants are refused instead of kept because downstream tooling that scans for the uppercase token would miss the break entirely.
Footer token "Reviewed by" is invalid — use letters, digits and hyphens in place of whitespace, e.g. Reviewed-by (Conventional Commits v1.0.0 §8–§9).- Footer tokens must be single word tokens so parsers can tell where a footer starts; the hyphen stands in for the space. Only BREAKING CHANGE may contain one.
FAQ
What are Conventional Commits?
A lightweight convention for commit messages, frozen as specification v1.0.0, that gives every commit a machine-readable header of the form type(scope)!: description plus optional body and footers. Because the shape is predictable, tools can derive changelogs, trigger releases and enforce history rules straight from the messages instead of asking humans to remember what changed.
Which commit types exist?
The specification itself only defines feat and fix and allows anything else. In practice most projects adopt the eleven-type enum from config-conventional — feat, fix, docs, style, refactor, perf, test, build, ci, chore and revert — which is exactly the list in this tool's type select and the list the type-enum rule checks against.
How do breaking changes work?
Declare them in the header by appending ! after the type or scope, or in a footer that starts with BREAKING CHANGE: followed by a description of what broke, or both at once. The footer token is the only case-sensitive word in the grammar and must be uppercase; BREAKING-CHANGE with a hyphen is accepted as its synonym.
Is this the same as running commitlint?
No — nothing is installed or executed here. The Lint tab is this site's own implementation of nine rules under their commitlint-compatible ids, with the error and warning levels config-conventional assigns, running entirely in your browser. Findings should read the same as your CI's, but the authority for your repository is whatever configuration your repository pins.
Do scopes have a fixed list?
Not by default. The spec says a scope is a noun describing the affected section of the codebase, and config-conventional only requires it to be lowercase — there is no default scope-enum. Teams that want a closed list configure one in their own commitlint setup; this page checks case and shape but never invents a list for you.
How do Conventional Commits map to semantic versioning?
The spec recommends the mapping rather than mandates it: fix corresponds to a PATCH release, feat to a MINOR release, and any commit carrying a breaking-change marker — whatever its type — to a MAJOR release. Release tooling built on the convention reads exactly those three signals out of your history.
Keyboard shortcuts
- /
- Focus the first field of the active tab
- ⌘/Ctrl + S
- Download the message as commit-message.txt
- ⌘/Ctrl + C
- Copy the active tab's result when nothing is selected
- ⌘/Ctrl + Shift + C
- Copy the active tab's result
- t
- Cycle the color theme
- ? or ⌘/Ctrl + /
- Open this shortcut list
- Esc
- Close dialogs