Workbench

Commits

Conventional Commits, and why a commit message is written for the next developer.

The lesson first

In my first year, while rebuilding a Vue 2 app in Vue 3, my commit messages looked like this:

for backup
just for record
initial commit: error to be solved

I was committing to save my work, not to explain it. Months later, nobody could tell from the history what had changed or why, including me. Now every commit says what changed, in a format a tool can read too.

The format

type(scope): what changed, in the imperative
  • type: what kind of change it is (table below).
  • scope: the feature or area, matching a folder name where possible.
  • subject: lower case, no full stop, reads like a command: "add", not "added".
TypeUse it for
featA new feature or visible change for users
fixA bug fix
refactorA code change that doesn't change behaviour
styleFormatting only (lint fixes, whitespace)
docsDocumentation and written content about the project
choreTooling, dependencies, config
perfA performance improvement
testAdding or fixing tests

Real examples

From my portfolio's history:

feat(resume): implement PDF generation for résumé
feat(seo): per-page share metadata and built-in sitemap/robots
refactor(structure): move to src/ with feature folders per frontend rules
chore(tooling): adopt ultracite/biome and share cursor rules with claude
style: apply ultracite safe fixes
fix(animation): adjust bob animation duration and delay

A few rules of thumb

One change per commit

If the message needs "and", it's probably two commits. A lint-only change gets its own style: commit so it doesn't hide the real change in a diff.

Say why in the body when it isn't obvious

The subject says what. When the reason isn't clear from the diff, add a blank line and a short body:

fix(table): pass filters as an object instead of in the URL

The shared data table appends its own query string, so a URL that
already had "?" ended up with two, and paging params were lost.

Commit when it works, not when you're worried

If I want a backup of half-finished work, that's what a branch and a push are for. The commit on main should still explain itself.

Last updated on

On this page