The Complete Guide to Writing Better Git Commits
As developers, we write hundreds of commits throughout a project's lifetime. Yet, many of us treat commit messages as an afterthought. A well-written commit message is like leaving breadcrumbs for your future self (and your team) - it tells the story of why your code changed, not just what changed.
In this guide, I'll show you how to write professional commit messages with real examples from MERN stack and Next.js development.
Why Good Commits Matter
Imagine joining a project and seeing this in the git history:
- fixed stuff
- updates
- asdfasdf
- working now
- final fix (for real this time)Now compare that to this:
- feat: add user authentication with JWT
- fix: resolve memory leak in WebSocket connection
- refactor: extract API logic into service layer
- chore: upgrade Next.js to version 14Which project would you rather work on? Good commits:
- Help teammates understand changes without diving into code
- Make debugging easier by pinpointing when bugs were introduced
- Improve code reviews with clear context
- Generate meaningful changelogs automatically
- Show professionalism in your portfolio and open source contributions
The Conventional Commits Format
The most widely-used standard is Conventional Commits. Here's the structure:
<type>: <short description>
[optional body]
[optional footer]
Commit Types
Let me break down the most common types with real scenarios from MERN stack development:
feat: - New Features
When to use: Adding something NEW that users or clients will see or interact with.
Real examples:
feat: add user profile page with avatar upload
feat: implement dark mode toggle
feat: add pagination to blog posts
feat: create checkout page with Stripe integration
feat: add email verification on signup
feat: implement real-time notifications with Socket.io
feat: add product search with filters
feat: create admin dashboard for order management
feat: implement OAuth login with Google
feat: add markdown support for blog postsThink: "Would I demo this to a client or add it to release notes?" If yes → feat:
fix: - Bug Fixes
When to use: Correcting something that's broken or not working as intended.
Real examples:
fix: resolve 404 error on refresh in Next.js dynamic routes
fix: correct login redirect loop
fix: prevent duplicate orders on double-click
fix: resolve CORS error in production API
fix: correct profile image not displaying after upload
fix: resolve MongoDB connection timeout in deployment
fix: fix JWT token expiration handling
fix: correct cart total calculation for discounted items
fix: resolve hydration mismatch in SSR components
fix: prevent memory leak in useEffect cleanupThink: "Was something not working correctly before?" If yes → fix:
refactor: - Code Improvements
When to use: Restructuring or improving code WITHOUT changing its external behavior.
Real examples:
refactor: convert class components to functional hooks
refactor: extract API calls into separate service layer
refactor: split UserController into smaller modules
refactor: move validation logic to middleware
refactor: convert callback functions to async/await
refactor: reorganize folder structure for better scalability
refactor: simplify authentication logic using custom hook
refactor: replace prop drilling with Context API
refactor: optimize database queries with aggregation pipeline
refactor: extract repeated code into utility functionsThink: "Does the app do the exact same thing, just with cleaner code?" If yes → refactor:
chore: - Maintenance Tasks
When to use: Setup, configuration, dependencies, tooling - things that don't affect the app's functionality.
Real examples:
chore: add .gitignore with node_modules and .env
chore: update Next.js to version 14
chore: configure ESLint and Prettier rules
chore: add Husky pre-commit hooks
chore: setup MongoDB connection pooling
chore: configure environment variables for production
chore: add Docker configuration files
chore: update package dependencies to latest versions
chore: setup CI/CD pipeline with GitHub Actions
chore: configure Vercel deployment settings
chore: add TypeScript configurationThink: "Is this about tooling, setup, or dependencies - not app features?" If yes → chore:
Other Useful Types
docs: # Documentation only changes
docs: add API documentation for payment endpoints
docs: update README with deployment instructions
style: # Formatting, missing semicolons (no code change)
style: format code with Prettier
style: fix indentation in components folder
test: # Adding or updating tests
test: add unit tests for authentication service
test: add integration tests for checkout flow
perf: # Performance improvements
perf: optimize image loading with lazy loading
perf: add Redis caching for frequently accessed data
build: # Build system or external dependencies
build: configure Webpack for production optimization
build: add compression plugin to build processReal Day in MERN Development
Let me show you what a typical development day looks like with proper commits:
Monday Morning - Project Setup
git commit -m "chore: initialize Next.js project with TypeScript"
git commit -m "chore: install and configure Tailwind CSS"
git commit -m "chore: setup MongoDB Atlas connection"
git commit -m "chore: configure environment variables"Monday Afternoon - Authentication
git commit -m "feat: create user registration API endpoint"
git commit -m "feat: add login page with form validation"
git commit -m "feat: implement JWT token generation"Tuesday - Bug Fixes & Features
git commit -m "fix: resolve password hashing issue in signup"
git commit -m "feat: implement protected routes with middleware"
git commit -m "feat: add user profile page"Wednesday - Products Feature
git commit -m "feat: add product listing page with MongoDB queries"
git commit -m "feat: create shopping cart functionality"
git commit -m "refactor: extract product card into reusable component"
git commit -m "feat: implement cart persistence with localStorage"Thursday - Checkout & Refinements
git commit -m "fix: correct cart not persisting after page refresh"
git commit -m "feat: add checkout page with order summary"
git commit -m "refactor: move all API routes to /api/v1 structure"
git commit -m "feat: integrate Stripe payment processing"Friday - Polish & Deploy
git commit -m "fix: resolve Next.js Image optimization errors"
git commit -m "perf: add image lazy loading for product gallery"
git commit -m "chore: add README with setup instructions"
git commit -m "chore: update dependencies before deployment"
git commit -m "docs: add API documentation"Writing the Perfect Commit Message
The Subject Line
Rules:
- Use imperative mood - "add" not "added" or "adds"
- Keep it under 50 characters
- Don't end with a period
- Capitalize the first letter after the type
- Be specific but concise
✅ Good:
feat: add user authentication with JWT
fix: prevent crash when email field is empty
refactor: extract validation logic to utils❌ Bad:
feat: added some new features for users
fixed bug
update
changed filesThe Body (Optional but Valuable)
Add a body when you need to explain the why behind your changes:
fix: prevent memory leak in WebSocket connection
The connection wasn't being properly closed when users
navigated away from the chat page, causing memory to
accumulate over time. Now explicitly closing connections
in the useEffect cleanup function.
This resolves the performance degradation reported by
users after extended app usage.When to add a body:
- The change is complex or non-obvious
- You're fixing a bug (explain what caused it)
- There are important tradeoffs or decisions made
- The change has implications for other parts of the codebase
The Footer (For Special Cases)
feat: add user profile deletion
Allow users to permanently delete their accounts and
all associated data in compliance with GDPR requirements.
BREAKING CHANGE: API endpoint /api/user now requires
authentication header for all requestsQuick Decision Tree
Not sure which type to use? Follow this:
┌─ Is it visible to users or adds functionality?
│ └─ Yes → feat:
│
├─ Is it fixing something broken?
│ └─ Yes → fix:
│
├─ Is it improving code without changing behavior?
│ └─ Yes → refactor:
│
├─ Is it tests?
│ └─ Yes → test:
│
└─ Is it tooling, config, or dependencies?
└─ Yes → chore:
Best Practices & Tips
1. Commit Often, Commit Early
Don't wait until you have 500 lines changed. Make small, logical commits:
# ❌ Bad - too much in one commit
git commit -m "feat: add entire user authentication system"
# ✅ Good - broken into logical pieces
git commit -m "feat: create user registration endpoint"
git commit -m "feat: add login form with validation"
git commit -m "feat: implement JWT token generation"
git commit -m "feat: add protected route middleware"2. One Concern Per Commit
# ❌ Bad - mixing concerns
git commit -m "feat: add login page and fix cart bug and update packages"
# ✅ Good - separate commits
git commit -m "feat: add user login page"
git commit -m "fix: resolve cart total calculation bug"
git commit -m "chore: update React and Next.js versions"3. Test Before You Commit
Your code should work before you commit it. Don't commit broken code (except on feature branches with WIP notation).
4. Use Commit Templates
Create a .gitmessage template:
# ~/.gitmessage
# <type>: <subject>
#
# <body>
#
# <footer>
# Type: feat, fix, refactor, chore, docs, style, test, perf
# Subject: imperative mood, 50 chars max, no period
# Body: explain what and why (72 chars per line)
# Footer: breaking changes, issue referencesThen configure git:
git config --global commit.template ~/.gitmessage5. Leverage Git Hooks
Use Husky to enforce commit conventions:
npm install --save-dev husky @commitlint/cli @commitlint/config-conventional
# package.json
{
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}Tools to Help You
Commitizen
Interactive CLI for writing commits:
npm install -g commitizen
commitizen init cz-conventional-changelog --save-dev --save-exactThen use git cz instead of git commit
VSCode Extensions
- Conventional Commits - Helps write proper commits
- GitLens - Visualize commit history beautifully
Automated Changelog Generation
Tools like standard-version can generate changelogs from your commits:
npm install --save-dev standard-version
# Creates CHANGELOG.md automatically
npm run releaseCommon Mistakes to Avoid
1. Vague Messages
❌ git commit -m "updates"
❌ git commit -m "fixes"
❌ git commit -m "changes"
✅ git commit -m "fix: resolve CORS error in production API"2. Too Much in One Commit
❌ git commit -m "feat: add entire e-commerce system"
✅ Split into: product listing, cart, checkout, payment3. Mixing Types
❌ git commit -m "feat: add login and fix navbar bug"
✅ Separate into feat and fix commits4. Irrelevant Details in Subject
❌ git commit -m "fix: updated the LoginComponent.tsx file on line 45"
✅ git commit -m "fix: resolve authentication redirect loop"Real-World Examples from Open Source
Let's look at commits from popular projects:
Next.js:
feat: add support for React Server Components
fix: resolve hydration mismatch in app directory
perf: optimize bundle size for production builds
docs: update deployment guide for VercelReact:
feat: add useId hook for SSR-safe unique IDs
fix: prevent memory leak in useEffect
refactor: simplify reconciliation algorithm
test: add integration tests for SuspenseConclusion
Good commit messages are a hallmark of professional developers. They:
- Make your code history readable and useful
- Help your team (and future you) understand changes
- Show attention to detail in your portfolio
- Make debugging and code reviews much easier
Start small - focus on getting the type and short description right. As you build the habit, add bodies to complex changes. Your future self will thank you!
Quick Reference Card
feat: New feature for users
fix: Bug fix
refactor: Code improvement (no behavior change)
chore: Tooling, config, dependencies
docs: Documentation only
style: Formatting (no code change)
test: Adding or updating tests
perf: Performance improvement
Format: type: imperative description under 50 chars
Body: Explain WHY (optional)
Footer: Breaking changes, issues (optional)Resources:
Happy committing! 🚀
What are your commit message tips? Share them in the comments below!