Commit conventions (Conventional Commits)

Why a convention for commit messages

A commit message is a note to the future — to you and the team six months from now. Conventional Commits is a simple standard that gives messages structure, so that history stays readable and tools can generate changelogs and version numbers from it.

Format

<type>(<optional scope>): <description>

<optional body>

<optional footer>

Examples:

feat(dashboard): dodaj widżet MFA
fix(auth): popraw redirect po wygaśnięciu sesji
docs(readme): uzupełnij instrukcję deployu
refactor(api): wydziel walidację do osobnej funkcji

Commit types

TypeMeaning
featNew functionality
fixBug fix
docsDocumentation only
styleFormatting, no logic change
refactorCode change with no new feature or fix
testAdding/improving tests
choreConfiguration, dependencies, tooling
ciChanges to the CI/CD pipeline
perfPerformance optimization

The types map to semantic versioning:

  • fix: → a PATCH bump (1.2.3 → 1.2.4)
  • feat: → a MINOR bump (1.2.3 → 1.3.0)
  • BREAKING CHANGE → a MAJOR bump (1.2.3 → 2.0.0)

You flag a breaking change with ! or a footer:

feat(api)!: zmień format odpowiedzi raportów

BREAKING CHANGE: pole "total" zwraca teraz wartość netto zamiast brutto.

Tip: Write the description in the imperative, as if completing the sentence "If applied, this commit will …": "add X", "fix Y" — not "added", "adds". This is the convention used by Git itself.

Enforcing the convention in CI

You can check the format automatically. Locally via the commitlint hook, and in the pipeline as a GitHub Actions step:

name: Lint commits
on: [pull_request]
jobs:
  commitlint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: wagoid/commitlint-github-action@v6

Good habits

  1. One commit = one logical change.
  2. First line ≤ ~72 characters, no period at the end.
  3. In the commit body explain why, not just what (the what is visible in the diff).
  4. A scope (dashboard, auth) makes searching the history easier.

The end benefit

Consistent commits let tools like release-please or semantic-release automatically create the changelog and tag versions based on the history alone — zero manual release notes.

Summary

Conventional Commits is a small cost and a big convenience: type(scope): description in the imperative mood. The types map to SemVer, and CI with commitlint guards the format. The result is a readable history and automatic changelogs.