Markdownlint Configuration Guide: Unifying Your Team's Documentation Style

Markdownlint guide illustration

Why Do We Need Markdownlint?

Have you ever encountered this scenario: team members submit Markdown documents with wildly different formatting styles—some prefer two-space indentation while others use four spaces; some leave blank lines around headings while others don’t; some specify languages for code blocks while others leave them plain. This inconsistency not only affects readability but also creates unnecessary formatting diffs during code reviews.

Markdownlint was created to solve exactly this problem. It’s a specialized tool for checking Markdown file formatting standards that can:

  • Unify formatting standards: Ensure all team members follow the same Markdown writing conventions
  • Catch issues early: Discover formatting problems before publication, preventing display issues in production
  • Improve reading experience: Consistent formatting makes documentation more readable and user-friendly
  • Reduce code review overhead: Automated format checking lets reviewers focus on content rather than style

Using Markdownlint in Code Editors

VS Code Extension Installation

For daily writing, the most convenient approach is installing the markdownlint extension in VS Code:

  1. Open VS Code
  2. Open the Extensions panel (marketplace)
  3. Search for “markdownlint”
  4. Install the “markdownlint” extension (by DavidAnson)

Once installed, when you open Markdown files, the extension automatically checks formatting issues and displays green wavy underlines in the editor. Hovering over problem areas shows specific error messages and rule numbers.

Real-time Format Checking

The extension provides multiple ways to view and fix issues:

  • Inline hints: Green wavy underlines appear below problematic code
  • Problems panel: Press Ctrl+Shift+M (Mac users press Cmd+Shift+M) to open the problems panel and view all formatting issues
  • Status bar display: The editor’s bottom status bar shows the current file’s issue count
  • Quick fix: For auto-fixable issues, use Ctrl+Shift+P to open the command palette and run “markdownlint: Fix all”
  • Workspace checking: Run “markdownlint: Lint workspace” to check all Markdown files in the workspace

When you fix issues, the hints disappear in real-time, letting you immediately see the results of your changes.

Using Markdownlint from Command Line

markdownlint-cli vs markdownlint-cli2

When choosing command-line tools, it’s important to understand the differences between the two main versions:

  • markdownlint-cli: The original command-line tool with relatively basic functionality
  • markdownlint-cli2: The next-generation command-line tool with more powerful features and flexible configuration

Important Note: VS Code’s markdownlint extension uses the markdownlint-cli2 engine under the hood, so we recommend using markdownlint-cli2 in the command line as well for consistency. markdownlint-cli2 supports richer configuration file formats (.markdownlint-cli2.jsonc, .markdownlint-cli2.yaml, .markdownlint-cli2.cjs) and provides better performance and extensibility.

Global Installation

For scenarios requiring batch file checking or build process integration, command-line tools are more suitable:

# Install globally with npm
npm install -g markdownlint-cli2

# Or with yarn
yarn global add markdownlint-cli2

# Or with pnpm
pnpm add -g markdownlint-cli2

Basic Usage

After installation, you can check files with these commands:

# Check a single file
markdownlint-cli2 README.md

# Check multiple files
markdownlint-cli2 docs/*.md

# Check entire directory
markdownlint-cli2 docs/

# Recursively check all subdirectories
markdownlint-cli2 "**/*.md"

Common Command Options

# Auto-fix fixable issues
markdownlint-cli2 --fix docs/*.md

# Specify configuration file
markdownlint-cli2 --config .markdownlint-cli2.jsonc docs/*.md

# Output verbose information
markdownlint-cli2 --verbose docs/*.md

# Ignore specific files
markdownlint-cli2 --ignore node_modules docs/*.md

Custom Configuration: Creating .markdownlint-cli2.jsonc

Configuration File Basics

Markdownlint’s power lies in its highly customizable configuration system. You can flexibly adjust various checking rules based on your team’s writing habits and project requirements. Create a .markdownlint-cli2.jsonc file in your project root:

{
  "default": true,
  "MD003": { "style": "atx" },
  "MD007": false,
  "MD013": false,
  "MD022": false,
  "MD024": { "siblings_only": true },
  "MD025": false,
  "MD029": false,
  "MD031": false,
  "MD032": false,
  "MD033": false,
  "MD040": false,
  "MD041": false
}

Common Rules Explained

Let’s dive into several important rules:

MD003 - Heading Style

"MD003": { "style": "atx" }

Enforces ATX-style headings (# Heading) rather than Setext-style (Heading\n====).

MD013 - Line Length Limit

"MD013": { "line_length": 120 }

Limits maximum characters per line. Set to false to disable this rule.

MD024 - Duplicate Headings

"MD024": { "siblings_only": true }

Allows identical headings in different sections, but prevents duplicate sibling headings.

MD040 - Code Block Language

"MD040": true

Requires code blocks to specify programming languages for better syntax highlighting.

Project-Specific Configuration Examples

Different project types may require different configurations:

Technical Documentation Project:

{
  "default": true,
  "MD013": { "line_length": 100 },
  "MD040": true,
  "MD041": false
}

Blog Project:

{
  "default": true,
  "MD013": false,
  "MD033": false,
  "MD041": false
}

Automation: Integrating into Development Workflow

Editor Automation

Modern editors typically support format-on-save functionality. In VS Code, you can configure workspace settings to enable automatic fixing on save:

{
  "editor.codeActionsOnSave": {
    "source.fixAll.markdownlint": true
  }
}

This configuration automatically runs markdownlint fixes every time you save a Markdown file, ensuring format compliance at all times.

Automated Fixing with Claude Code Hooks

Beyond editor plugins, we can leverage Claude Code Hooks for deeper automation. Hooks are user-defined shell commands that execute automatically at specific points in Claude Code’s lifecycle (e.g., after tool usage).

We can configure a PostToolUse hook to automatically run markdownlint-cli2 --fix after Claude edits or creates Markdown files. This ensures format consistency whether we’re manually editing or having Claude generate content.

Configuration Method:

Run the /hooks command in Claude Code, select the PostToolUse event, and add the following configuration. This hook matches all file write operations (Edit|MultiEdit|Write), parses the file path using jq, and executes the fix command if it’s a Markdown file (.md).

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.md$'; then markdownlint-cli2 --fix \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Through this approach, formatting becomes a seamless, automated part of the development process rather than something developers need to remember or manually trigger.

Git Hooks Tool Selection: Husky vs Pre-commit vs Simple-git-hooks

When configuring Git Hooks, multiple tools are available, each with pros and cons suitable for different tech stacks and team preferences.

ToolPrimary Language/EcosystemProsConsBest Use Cases
HuskyJavaScript/Node.jsPowerful features, mature ecosystem, excellent experience with lint-stagedSlightly complex configuration, requires Node.jsFrontend projects, especially React, Vue, Astro
simple-git-hooksJavaScript/Node.jsLightweight, zero dependencies, simple configurationBasic functionality, less mature ecosystemNode.js projects prioritizing simplicity
pre-commitPythonGood cross-language support, YAML configuration, not tied to specific ecosystemsRequires Python environment, less native for frontendMulti-language projects, especially with Python, Go, Rust backends

For pure frontend or JavaScript-centric projects, Husky is usually the best choice. For projects with multiple backend languages, pre-commit’s cross-language capabilities offer advantages. simple-git-hooks suits teams wanting lightweight toolchains.

Configuring Hooks with Husky

Husky is currently the most popular Git Hooks management tool for Node.js projects. It works perfectly with lint-staged to check only staged files.

1. Install dependencies:

pnpm add -D husky lint-staged

2. Configure package.json:

{
  "scripts": {
    "postinstall": "husky install"
  },
  "lint-staged": {
    "*.md": "markdownlint-cli2 --fix"
  }
}

3. Create pre-commit hook:

npx husky add .husky/pre-commit "npx lint-staged"

Configuration explanation:

  • lint-staged only checks staged files for better performance
  • markdownlint-cli2 --fix automatically fixes repairable issues
  • The "postinstall" script ensures hooks are properly set up after each dependency installation

Configuring Hooks with simple-git-hooks

If you prefer a simpler, zero-dependency solution, simple-git-hooks is a good choice.

1. Install dependencies:

pnpm add -D simple-git-hooks

2. Configure package.json:

{
  "simple-git-hooks": {
    "pre-commit": "pnpm exec markdownlint-cli2 --fix '**/*.md'"
  },
  "scripts": {
    "postinstall": "simple-git-hooks"
  }
}
  • The "simple-git-hooks" object defines which commands execute at which hook triggers
  • The "postinstall" script ensures hooks are properly set up after dependency installation

3. Update hooks: Manually run pnpm postinstall once or reinstall dependencies.

Configuring Hooks with Pre-commit

To ensure all committed documents meet formatting standards, we can configure pre-commit hooks:

1. Install pre-commit:

# macOS
brew install pre-commit

# Or use pip
pip install pre-commit

2. Create .pre-commit-config.yaml:

repos:
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.37.0
    hooks:
      - id: markdownlint-fix
        args: ['--config', '.markdownlint-cli2.jsonc']

3. Install hooks:

pre-commit install

CI/CD Integration

You can also integrate markdownlint checking into continuous integration workflows:

GitHub Actions Configuration

markdownlint-cli2 officially recommends using its dedicated GitHub Action markdownlint-cli2-action, which greatly simplifies configuration.

Create .github/workflows/markdownlint.yml in your project root:

name: Markdown Lint
on: [push, pull_request]

jobs:
  markdownlint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run markdownlint-cli2
        uses: DavidAnson/markdownlint-cli2-action@v16
        with:
          # Optional: specify configuration file path
          config: .markdownlint-cli2.jsonc
          # Optional: fix discovered issues
          # fix: true

This workflow automatically runs markdownlint checks on every push and pull request, ensuring all code merged to the main branch meets documentation standards.

Through these configurations, we establish a complete documentation quality assurance system:

  • Local development: Real-time editor hints + auto-fixing
  • Commit stage: Git hooks automatic checking and fixing
  • CI/CD stage: Automated checking prevents non-compliant content merging

Automation Flow Chart

This automation flow chart clearly shows the complete quality assurance loop from local development to continuous integration, ensuring documentation meets standards at every stage.

                    ┌─────────────────────────────┐
                    │   Developer Edits Markdown  │
                    └─────────────┬───────────────┘


                    ┌─────────────────────────────┐
                    │    Automated Fix Trigger    │
                    │  (On Save / After Tool Use) │
                    └─────────────┬───────────────┘

                    ┌─────────────┴───────────────┐
                    │                             │
          ┌─────────▼─────────┐         ┌─────────▼─────────┐
          │   Editor Plugin   │         │   Claude Hooks    │
          │ (Format on Save)  │         │    (Optional)     │
          │  Real-time Check  │         │  Post-tool Fix    │
          └─────────┬─────────┘         └─────────┬─────────┘
                    │                             │
                    └─────────────┬───────────────┘


                    ┌─────────────────────────────┐
                    │    Developer Commits Code   │
                    │       (git commit)          │
                    └─────────────┬───────────────┘


                    ┌─────────────────────────────┐
                    │    Git Pre-commit Hook      │
                    │  (Husky/simple-git-hooks)   │
                    │    Final Format Check       │
                    └─────────────┬───────────────┘

                                  ▼ (Check Passes)
                    ┌─────────────────────────────┐
                    │     Push to Remote Repo     │
                    │    (git push origin)        │
                    └─────────────┬───────────────┘


                    ┌─────────────────────────────┐
                    │     CI/CD Pipeline Trigger  │
                    │  (GitHub Actions/GitLab)    │
                    │    Final Quality Check      │
                    └─────────────┬───────────────┘


                    ┌─────────────────────────────┐
                    │    Deploy to Production     │
                    │   (Documentation Quality    │
                    │        Guaranteed)          │
                    └─────────────────────────────┘

Conclusion

Markdownlint is more than just a format checking tool—it represents an important practice of the “docs as code” philosophy in modern software development. Through unified documentation format standards, we can:

  • Improve team collaboration efficiency: Reduce communication costs caused by formatting issues
  • Enhance user experience: Standardized document formatting provides better reading experiences
  • Build a quality culture: Elevate documentation quality to the same importance as code quality
  • Achieve automated management: Use tooling to reduce manual intervention and improve work efficiency

In this information-rich era, high-quality documentation has become one of the key factors for project success. Tools like markdownlint help us build a moat of documentation quality, allowing technical teams to focus on creating value rather than getting bogged down in formatting details.

Starting today, configure markdownlint for your projects and make documentation standards your team’s common language.

Comments