commitlint checks that Git commit messages follow the Conventional Commits format (type(scope): subject) and fails when they do not. Use when a user asks to standardize commit messages, enforce commit conventions with a husky commit-msg hook, lint commits or PR commits in CI, customize rules, or prepare commits for automated changelogs and semantic versioning.
142 stars
0 votes
0 copies
1 view
Added May 27, 2026
developmentjavascriptgojavabashnodegitapi
Works with
terminal
cli
api
Security analysis
A96/100
mediumInstalls packages at runtime which could introduce malicious dependencies
Installs into .claude/skills of the current project.
Are you the author of Commitlint?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/terminalskills-commitlint)
---
name: commitlint
description: >-
commitlint checks that Git commit messages follow the Conventional Commits format (type(scope): subject) and fails when they do not. Use when a user asks to standardize commit messages, enforce commit conventions with a husky commit-msg hook, lint commits or PR commits in CI, customize rules, or prepare commits for automated changelogs and semantic versioning.
license: Apache-2.0
compatibility: "Node.js 22.12 or newer, git 2.13.2 or newer, any Git repository"
metadata:
author: terminal-skills
version: "1.1.0"
category: development
repository: https://github.com/conventional-changelog/commitlint
tags:
- commitlint
- git
- conventional-commits
- ci
- changelog
---
# commitlint
## Overview
commitlint (`@commitlint/cli`, v21 at the time of writing) lints a commit message against a rule set; the usual rule set is `@commitlint/config-conventional`, which enforces `type(scope?): subject`. It requires Node.js 22.12 or newer. It runs in a Git `commit-msg` hook (typically via husky) and in CI. Valid messages let tools such as semantic-release, release-please, changesets or conventional-changelog derive version bumps and changelogs.
## Instructions
### Step 1: Install and add the hook (husky v9)
```bash
npm install -D @commitlint/cli @commitlint/config-conventional husky
npx husky init
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg
```
`npx husky init` also creates `.husky/pre-commit` containing `npm test`, which makes every commit fail in a project without tests. Edit or empty that file if you do not want it.
### Step 2: Configure
Create `commitlint.config.mjs` (or `commitlint.config.js` with `"type": "module"`, `.cjs`, `.ts`, `.commitlintrc.*`, or a `commitlint` key in `package.json`).
```javascript
// commitlint.config.mjs
export default {
extends: ['@commitlint/config-conventional'],
rules: {
// [severity, applicable, value]; severity 0 off, 1 warning, 2 error
'scope-enum': [2, 'always', ['auth', 'api', 'billing', 'ui', 'deps']],
'scope-case': [2, 'always', 'kebab-case'],
'header-max-length': [2, 'always', 72],
},
}
```
The default `type-enum` is build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test. If you override `type-enum`, repeat the types you still want, including `revert`. Default config-conventional limits headers and body/footer lines to 100 characters and forbids sentence-case subjects and trailing periods.
### Step 3: Try it
```bash
echo "updated stuff" | npx commitlint # exit 1: subject and type may not be empty
echo "feat(auth): add Google OAuth login" | npx commitlint # exit 0
git commit -m "fix(api): handle null response from /users" # hook runs commitlint
```
### Step 4: Lint in CI
```yaml
# .github/workflows/commitlint.yml
name: commitlint
on: [pull_request]
jobs:
commitlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose
```
Other useful forms: `npx commitlint --last` (latest commit), `--from origin/main` (everything since main), `--config path` for a non-default config. If you squash-merge, lint the PR title instead of the individual commits.
## Examples
### Example 1: Add commit linting to an existing repo
**User request:** "Make everyone on the team use conventional commits."
Run Step 1 and Step 2, empty `.husky/pre-commit` if the repo has no `npm test`, and commit `commitlint.config.mjs` and `.husky/`. Then `git commit -m "updated stuff"` is rejected with `type may not be empty [type-empty]`, and `git commit -m "feat(billing): add annual plan"` succeeds. Add a `prepare` script (`"prepare": "husky"`, which `husky init` sets) so teammates get hooks after `npm install`.
### Example 2: Restrict scopes to the monorepo packages
**User request:** "Only allow scopes that match our package names."
Set `'scope-enum': [2, 'always', ['web', 'api', 'worker']]`. Then `echo "feat(mobile): add push" | npx commitlint` exits 1 with `scope must be one of [web, api, worker] [scope-enum]`, while `fix(api): retry on 503` passes.
## Guidelines
- Hooks can be bypassed with `git commit --no-verify`; keep the CI check as the enforcement point.
- Merge and revert commits generated by Git are ignored by default; do not disable that.
- `subject-max-length` does not exist in config-conventional by default; the header limit is `header-max-length` (100).
- Breaking changes use `feat!:` or a `BREAKING CHANGE:` footer and map to a major version; `feat` maps to minor, `fix` to patch.
- commitlint only lints messages; it does not generate changelogs. Pair it with a release tool.
- On older Node versions install an older commitlint major; v21 needs Node 22.12 or newer.