Validate your Markdown files with markdownlint
TL;DR
- Use
markdownlint-cli2to lint Markdown from the CLI.- Put global rules in a root
.markdownlint.json.- For folder-specific exceptions, add a nested
.markdownlint.jsonthatextendsthe root config.
Why lint Markdown
Linting Markdown helps teams agree on a baseline style without micromanaging every doc. It also surfaces structural issues (like missing top-level headings) in the editor, so fixes happen while you write instead of during reviews.
The markdownlint tool
markdownlint is the rule engine and markdownlint-cli2 is the config-driven CLI that runs it. There are many rules (for example MD013 and MD041), and the goal is to set a sensible baseline, then tune only what does not fit your content.
Useful references:
- Rules list: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
- markdownlint configuration: https://github.com/DavidAnson/markdownlint/blob/main/README.md#configuration
- markdownlint-cli2 configuration files and options: https://github.com/DavidAnson/markdownlint-cli2#configuration
Install and run in a project:
If you use Neovim, you can install a markdownlint binary via Mason so your editor tooling can run the linter locally. Pick the package that matches your setup (for example, markdownlint or markdownlint-cli2), then wire it into your linting plugin.
Global rules and folder-specific overrides
Start with global rules in a root .markdownlint.json so the whole repository has a consistent baseline:
For folder-specific behaviour, add a nested config file and extends the root config. This is the reliable approach when a rule should only be relaxed in one area:
In this example, command docs can skip MD041 (first line should be a top-level heading), while the rest of the project keeps stricter defaults.
Example layout for folder-specific rules with nested .markdownlint.json files:
The nested config inherits the root rules via extends (see the example snippet above), then overrides just the rules that don't apply to that folder.
Note: overrides is not a valid key in .markdownlint.json. If you need top-level CLI options such as globs, ignores, or gitignore, use a .markdownlint-cli2.* config instead.