← Back to Tools

Conventional Commits

A quick guide for game dev teams — programmers and artists alike

feat fix refactor perf build test docs chore wip breaking

The Format

Every commit message follows this structure. The type says what kind of change it is, the scope is optional and says where, and the description says what you did — in imperative mood (e.g. "add", not "added").

type(scope): short description in imperative mood │ │ │ │ │ └─ What you did (lowercase, no period) │ └───────────────── Where in the project (optional) └───────────────────────── What kind of change
feat
Features
New functionality for the player or pipeline

Use feat when you add something new — a mechanic, a UI screen, a tool, or any user-facing capability. Each commit on a feature branch is still a feat if it adds working functionality, even if it's just one piece of a bigger feature.

feat(combat): add heavy attack with charged input feat(ui): add health bar to player HUD feat(inventory): implement drag-and-drop between slots feat: add main menu with play and quit buttons
fix
Fixes & Hotfixes
Something was broken, now it works

Use fix for bug fixes — anything that corrects wrong behavior. For urgent production fixes (hotfixes), still use fix but on a hotfix/ branch per Git Flow.

Regular fixes
fix(audio): stop SFX playing twice on hit fix(physics): correct wall clip on dash fix(save): handle corrupted save file gracefully
Hotfixes (same type, different branch)
// on branch: hotfix/crash-on-load fix(loader): prevent null ref on scene load // merged directly into main + develop
docs
Documentation
README, comments, wikis, guides

Use docs when the commit only changes documentation — READMEs, code comments, wiki pages, or setup guides. No gameplay or code logic changes.

docs: add setup instructions for new contributors docs(api): add XML summary comments to save system docs(art): document sprite naming conventions
chore
Chores & Maintenance
Cleanup, config, dependencies — no new features

Use chore for housekeeping that doesn't affect gameplay or fix bugs — updating packages, tweaking editor settings, cleaning up .meta files, or importing raw assets. Also useful: asset (a custom type for art/audio imports).

chore: update Unity from 2022.3.10 to 2022.3.20 chore(editor): add custom inspector for enemy spawner chore: remove unused materials from Resources folder asset(audio): add footstep SFX for grass and stone
build
Build System
Build pipeline, external dependencies, CI/CD

Use build for changes to the build pipeline, project settings, platform targets, or external dependencies. This includes Unity's Player Settings, Addressables config, CI scripts, and package manager updates. For CI-only changes you can also use ci as an alternative type.

build: switch target platform from Windows to WebGL build(addressables): add remote asset bundle profiles build: upgrade URP package to 14.0.9 ci: add GitHub Actions workflow for nightly builds
perf
Performance
Faster, leaner, smoother — no new behavior

Use perf when the commit improves performance without changing what the game does — draw call batching, object pooling, LOD tuning, reducing allocations. The behavior stays the same, it just runs better. Think of it as a special kind of refactor focused purely on speed or memory.

perf(combat): pool projectiles instead of instantiating each shot perf(rendering): enable GPU instancing on foliage materials perf(ai): switch pathfinding to job system for batch queries
refactor
Refactor
Restructure code or project — same behavior, better organization

Use refactor when you reorganize or clean up without adding features or fixing bugs. This applies to code (extracting interfaces, renaming classes) and project structure (reorganizing art folders, renaming assets, consolidating prefabs). The game works exactly the same before and after.

Code refactors
refactor(combat): extract IDamageable interface refactor(ui): replace singletons with SO events refactor: rename Player to PlayerController
Art & folder refactors
refactor(art): reorganize sprites into per-biome folders refactor(prefabs): flatten nested enemy prefab hierarchy refactor: rename all UI assets to follow naming guide
test
Tests
Add, update, or fix automated tests

Use test when the commit only touches tests — adding new ones, fixing broken ones, or improving coverage. No production code changes. If you add a feature and its tests in the same commit, use feat instead.

test(inventory): add unit tests for stack splitting logic test(save): add integration test for corrupted save recovery test(combat): fix flaky damage calculation test
wip
Work In Progress
Custom type — use only when you really need to save incomplete work

The spec allows custom types. Use wip when you must commit genuinely incomplete or non-functional code — e.g. saving progress before ending the day. Avoid overusing it. If your commit adds something that works on its own (even if the bigger feature isn't done), prefer feat or another standard type instead.

✗ Lazy — everything is WIP
wip: inventory stuff wip: more inventory stuff wip: almost done
✓ Specific, used only when truly incomplete
feat(inventory): add slot prefab and grid layout wip(inventory): partial drag logic, drop not working yet feat(inventory): complete drag-and-drop between slots

Scopes — optional but helpful

Scopes go inside parentheses after the type. They narrow down which part of the project was affected. Pick short, consistent names your whole team agrees on. Here are some common ones for game projects:

ui combat audio vfx ai save physics editor inventory animation input networking

If the change touches many areas, just omit the scope: feat: add pause menu


!
Breaking Changes
Something other people's code depends on just changed

If your commit changes an API, renames a public method, restructures shared ScriptableObjects, or anything that will break other people's work until they update, mark it with ! after the type (or scope), and optionally add a BREAKING CHANGE: footer in the commit body explaining what changed.

feat(save)!: switch save format from binary to JSON BREAKING CHANGE: Old binary save files are no longer compatible. Players must start a new game or migrate saves with the provided tool.
fix(combat)!: rename TakeDamage to ApplyDamage across all interfaces BREAKING CHANGE: All classes implementing IDamageable must rename TakeDamage() to ApplyDamage(). Search-and-replace should cover it.

Squashing on Merge
Keep develop clean — squash your feature branch into one commit

On your feature branch, commit freely with proper types. When merging into develop, squash everything into a single feat commit with a descriptive body summarizing what the feature includes. The branch history stays available if anyone needs the details.

Feature branch timeline — feature/inventory-system
// Day 1 feat(inventory): add InventoryManager and item ScriptableObject wip(inventory): rough layout for grid UI // Day 2 feat(inventory): complete grid UI with slot prefabs feat(inventory): implement drag-and-drop between slots fix(inventory): correct slot highlight staying active after drop // Day 3 feat(inventory): add item tooltip on hover asset(inventory): add item icons and pickup SFX test(inventory): add unit tests for stack splitting // Day 4 refactor(inventory): extract IInventorySlot interface perf(inventory): pool tooltip objects instead of creating per hover feat(inventory): add stack splitting with shift-click
✓ Squashed result on develop
feat(inventory): add complete inventory system - Grid-based UI with drag-and-drop - Item tooltips on hover - Stack splitting with shift-click - ScriptableObject-driven item data
Changelog Tools — these read your Conventional Commits and generate a changelog automatically:
standard-version — Node-based, generates CHANGELOG.md and bumps version tags.
release-please — Google's GitHub Action, creates release PRs automatically.
semantic-release — Fully automated versioning and publishing to npm/GitHub.
git-cliff — Fast, Rust-based, highly customizable, works with any repo.
cocogitto — Rust CLI that also validates commit messages before you push.
Don't overthink it. The goal is a readable history your whole team can follow — programmers and artists. When in doubt: pick the type that feels closest, write a clear description, and move on. Consistency beats perfection.