Commitlint Module
DevFlow writes a commitlint.config.mjs extending @commitlint/config-conventional, with a strict variant for commit types, subject case and header length.
The problem
Conventional Commits only work if something enforces them. Without enforcement, the history fills up with fixed stuff, update and WIP, and every changelog generator and semantic release tool downstream produces noise.
Enforcing it needs three pieces that have to agree with each other: the Commitlint configuration, the @commitlint/config-conventional preset, and a Git hook that actually runs it. Setting up only the configuration is the most common mistake — nothing checks anything until a human reads the changelog.
The command
npx create-devflow --only commitlintTo get the hook that runs it as well:
npx create-devflow --huskyGenerated files
commitlint.config.mjs — strict mode (default)
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert',
],
],
'subject-case': [2, 'never', ['start-case', 'pascal-case', 'upper-case']],
'header-max-length': [2, 'always', 100],
},
};commitlint.config.mjs — loose mode
export default {
extends: ['@commitlint/config-conventional'],
};Loose mode is available in the interactive wizard. It allows any type the Conventional Commits preset supports and does not enforce the subject case or the length limit.
Packages installed
| Package | Type |
|---|---|
@commitlint/cli | dev dependency |
@commitlint/config-conventional | dev dependency |
Scripts added
None. Commitlint is invoked from the .husky/commit-msg hook.
Manual setup versus DevFlow
The manual version is npm i -D @commitlint/cli @commitlint/config-conventional plus a commitlint.config.js. The configuration itself is one line — the value DevFlow adds is the strict preset, the commit-msg hook that runs it, and the fact that both are written in the same pass.
Limits
- The configuration alone does nothing. Without the
commit-msghook, Commitlint is never invoked locally. Apply the Husky module too, or add a Commitlint step to your CI pipeline. type-enumis restrictive by design. The strict list does not includeperfvariants beyond the base type, nor community types such aswiporhotfix. Add them to the list if your team uses them.subject-caserejects the whole subject, not just the first letter.feat: Add loginfails;feat: add loginpasses.- No
body-max-line-lengthrule is added, so long body lines are not rejected.
FAQ
Which commit types does the strict configuration allow?
feat, fix, docs, style, refactor, perf, test, build, ci, chore and revert.
Can I use Commitlint without Husky?
Yes. Delete .husky/commit-msg and add a Commitlint step to your CI pipeline instead, so pull requests are validated even if a developer commits without hooks.
Does Commitlint work with a monorepo?
Yes. The configuration file sits at the repository root, which is where the hook runs from.
Related
- Husky module — the hook that runs Commitlint
- Conventional Commits with Commitlint and Husky — the full walkthrough
- Git and Commits reference — every module in this category
lint-staged Module
DevFlow installs lint-staged and configures it to run ESLint and Prettier on staged files only, in package.json or a monorepo config file.
Vitest Module
DevFlow creates a vitest.config.ts with globals, a jsdom environment for React and Vue projects and V8 coverage, plus the test scripts.