Skip to content

commitlint

npm version License: MIT Node.js Conventional Commits

> Shared commitlint configuration for enforcing Conventional Commits across projects. Flexible design works out-of-the-box for any project, with optional scope restrictions.

  • 📝 Conventional Commits: Enforces Conventional Commits specification
  • 🎯 Flexible Scopes: No scope restrictions by default - works with any project structure
  • ⚙️ Configurable: Customizable scopes when you need them
  • 🚫 Custom Ignores: Ignore functions for merge commits, dependabot, etc.
  • 📦 TypeScript Support: Full type definitions included
Terminal window
pnpm add -D @jmlweb/commitlint-config @commitlint/cli @commitlint/config-conventional

> 💡 Upgrading from a previous version? See the Migration Guide for breaking changes and upgrade instructions.

Create a commitlint.config.js file in your project root:

import commitlintConfig from '@jmlweb/commitlint-config';
export default commitlintConfig;

That’s it! Any commit type/scope following Conventional Commits is allowed.

commitlint.config.js
import commitlintConfig from '@jmlweb/commitlint-config';
export default commitlintConfig;

Valid commits:

feat: add new feature
fix(auth): resolve login issue
chore(whatever-you-want): update deps
commitlint.config.ts
import { createCommitlintConfig } from '@jmlweb/commitlint-config';
export default createCommitlintConfig({
scopes: ['api', 'ui', 'database', 'auth', 'deps'],
});
import { createCommitlintConfig } from '@jmlweb/commitlint-config';
export default createCommitlintConfig({
scopes: ['core', 'utils', 'config'],
scopeRequired: true,
headerMaxLength: 72,
});
import { createCommitlintConfig } from '@jmlweb/commitlint-config';
export default createCommitlintConfig({
ignores: [
(commit) => commit.startsWith('Merge'),
(commit) => /^\[dependabot\]/.test(commit),
],
});

> Philosophy: Structured commit messages enable automation, improve collaboration, and make project history meaningful and navigable.

This package enforces Conventional Commits to standardize commit messages across teams. Structured commits aren’t just about consistency - they enable automated versioning, changelog generation, and make your git history actually useful for understanding project evolution.

Conventional Commits Format: Structured commit messages with types

  • Why: The Conventional Commits specification enables powerful automation like semantic-release (automatic versioning), automatic changelog generation, and better git history navigation. It forces developers to think about what their change actually does (feat vs fix vs refactor), which improves code review quality
  • Trade-off: Slightly more overhead when committing - must categorize changes. But the automation benefits and improved history are worth it
  • When to override: For personal projects where automation isn’t needed. But even solo developers benefit from clear commit history

No Scope Restrictions by Default: Works for any project structure

  • Why: Different projects have different scopes (monorepo packages, feature areas, components). Not enforcing scopes makes this config flexible and zero-configuration for most projects. Teams can add scope restrictions when needed
  • Trade-off: No validation that scopes make sense for your project. But this prevents the config from being opinionated about project structure
  • When to override: For monorepos or large projects, define allowed scopes to ensure consistency (e.g., ['api', 'ui', 'docs'])

100 Character Header Limit: Readable in all tools

  • Why: 100 characters fits comfortably in GitHub’s UI, terminal output, and git GUIs without wrapping. It’s long enough for descriptive messages but short enough to enforce conciseness. This makes git log and GitHub history readable
  • Trade-off: Sometimes you want longer descriptions. But that’s what the body is for
  • When to override: For teams that prefer shorter (72 chars) or longer headers. But 100 is a good standard

Flexible Scope Requirement: Optional by default

  • Why: Not all changes fit neatly into scopes. Making scopes optional allows quick commits while still enabling teams to enforce scopes when structure is important (like in monorepos where scope = package name)
  • Trade-off: Scopes aren’t enforced unless explicitly enabled
  • When to override: Set scopeRequired: true for monorepos or projects where scope categorization is important

This configuration enforces the Conventional Commits format:

<type>(<scope>): <subject>
[optional body]
[optional footer(s)]
feat(api): add user authentication endpoint
fix: correct date parsing logic
docs: update README with examples
chore(deps): update dependencies
refactor(ui): simplify form validation
test: add unit tests for utils
ci: add GitHub Actions workflow
TypeDescription
featNew feature
fixBug fix
docsDocumentation changes
choreMaintenance tasks
refactorCode refactoring
testAdding or updating tests
ciCI/CD configuration
perfPerformance improvements
styleCode style changes (formatting, etc.)
buildBuild system changes
revertReverting previous commits
OptionTypeDefaultDescription
scopesstring[]undefinedDefine allowed scopes (enables scope checking)
additionalScopesstring[][]Add scopes when extending base configs
additionalTypesstring[][]Additional commit types to allow
headerMaxLengthnumber100Maximum length for the header line
scopeRequiredbooleanfalseWhether to require a scope
bodyRequiredbooleanfalseWhether to require a commit body
ignores((commit: string) => boolean)[]undefinedFunctions to ignore certain commits
// Default config - no scope restrictions
import config from '@jmlweb/commitlint-config';
// Factory function for custom configs
import { createCommitlintConfig } from '@jmlweb/commitlint-config';
// Commit types constant
import { COMMIT_TYPES } from '@jmlweb/commitlint-config';

Use this configuration when you want:

  • ✅ Enforce Conventional Commits specification across your project
  • ✅ Automatic changelog generation from commit messages
  • ✅ Consistent commit message format across team members
  • ✅ Optional scope restrictions for monorepos
  • ✅ Integration with semantic-release or standard-version

For projects without commitlint, consider starting with this package to improve commit quality and enable automated versioning.

You can extend the configuration for your specific needs:

import { createCommitlintConfig } from '@jmlweb/commitlint-config';
export default createCommitlintConfig({
scopes: ['frontend', 'backend', 'shared', 'docs'],
additionalTypes: ['wip'], // Add work-in-progress type
});
import { createCommitlintConfig } from '@jmlweb/commitlint-config';
export default createCommitlintConfig({
scopes: ['core', 'api', 'ui'],
scopeRequired: true,
bodyRequired: true,
headerMaxLength: 72,
});
Terminal window
pnpm add -D husky
Terminal window
pnpm exec husky init

Create or edit .husky/commit-msg:

Terminal window
pnpm exec commitlint --edit $1
Terminal window
# This should fail
git commit -m "bad commit message"
# This should pass
git commit -m "feat: add new feature"
{
"scripts": {
"commitlint": "commitlint --edit",
"commitlint:all": "commitlint --from HEAD~10"
}
}
  • Node.js >= 18.0.0
  • @commitlint/cli >= 19.0.0
  • @commitlint/config-conventional >= 19.0.0

This package requires the following peer dependencies:

  • @commitlint/cli (>=19.0.0)
  • @commitlint/config-conventional (>=19.0.0)
  • commitlint - Lint commit messages according to conventional commits
  • Conventional Commits - A specification for adding meaning to commit messages
  • Husky - Git hooks made easy (recommended for pre-commit integration)
  • semantic-release - Automated versioning and changelog generation

> Note: If no breaking changes were introduced in a version, it’s safe to upgrade without additional steps.

No breaking changes have been introduced yet. This package follows semantic versioning. When breaking changes are introduced, detailed migration instructions will be provided here.

For version history, see the Changelog.

Need Help? If you encounter issues during migration, please open an issue.

See CHANGELOG.md for version history and release notes.

MIT