Linting Documentation with Vale and markdownlint
Documentation linting automates style and formatting checks. Learn how to configure Vale for prose style enforcement and markdownlint for Markdown formatting rules in your docs pipeline.
What You'll Learn
You will learn how to lint documentation for prose style and Markdown formatting, how to configure Vale with style guides, and how to integrate both tools into your CI pipeline.
Why It Matters
Manual proofreading is slow and inconsistent. Automated linting catches style violations, formatting errors, and terminology issues on every commit. It enforces consistency across all contributors without a human reviewer checking every detail.
Real-World Use
DodaTech uses Vale with the Google Developer Documentation Style Guide and markdownlint with project-specific rules. Every PR that fails linting is blocked from merging until issues are resolved.
flowchart LR A[Markdown File] --> B[Vale: Prose Linter] A --> C[markdownlint: Formatting Linter] B --> D[Style Violations] C --> E[Formatting Errors] D --> F[CI Blocks PR] E --> F F --> G[Writer Fixes Issues] G --> A A:::current classDef current fill:#f90,color:#fff,stroke:#333,stroke-width:2px
Configuring Vale
Vale is a prose linter that enforces style rules. Create a .vale.ini file in your project root:
# .vale.ini
StylesPath = .vale/styles
[formats]
markdown = md
[*]
BasedOnStyles = Vale, Google, write-good
[*.md]
Vale.Spelling = YES
Google.WordList = YES
write-good.E-Prime = NO
Install Vale and a style guide:
# Install Vale
brew install vale # macOS
# or: sudo snap install vale # Linux
# Download the Google style guide
mkdir -p .vale/styles
git clone https://github.com/errata-ai/google.git .vale/styles/Google
Running Vale
vale content/api/authentication.md
Expected output:
content/api/authentication.md
1:1 warning 'login' is informal. Use 'sign in'. Google.WordList
45:12 warning Use 'can' instead of 'may' Google.CanMay
89:5 error 'Utilize' is unnecessarily complex. Use 'use'. write-good.ComplexWords
Configuring markdownlint
markdownlint enforces Markdown formatting rules. Create a .markdownlint.json file:
{
"default": true,
"MD013": false,
"MD024": false,
"MD033": false,
"MD041": false,
"MD046": false
}
Running markdownlint
markdownlint content/
Expected output:
content/getting-started.md: 1:1 MD041/first-line-heading
First line in a file should be a top-level heading
content/installation.md: 25 MD009/no-trailing-spaces
Trailing spaces (line 25)
Creating Custom Vale Rules
# .vale/styles/DodaTech/Terminology.yml
extends: substitution
message: "Use '%s' instead of '%s'"
level: error
swap:
"click on": "select"
"click here": "visit"
"login": "sign in"
"utilize": "use"
"please": (remove)
"login": "sign in"
"setup" (noun): "set up" (verb)
Integrating Linters into CI
- name: Lint documentation
run: |
markdownlint-cli2 content/
vale content/
Both tools return non-zero exit codes when they find violations, causing the CI pipeline to fail.
Common Mistakes
1. Ignoring Linting Errors
Linting errors that are always bypassed become noise. Either fix the rule or disable it. Never leave errors in the output that no one acts on.
2. Using Too Many Rules
Starting with 200+ rules overwhelms writers. Begin with 10-20 essential rules and add more as the team adapts.
3. Not Customizing Rules
Default rule sets may conflict with your style guide. Customize Vale rules to match your terminology and tone.
4. Running Linters Only Locally
Linters run locally catch nothing when writers forget to run them. Always enforce linting in CI.
5. Not Documenting the Rules
Writers need to know what rules exist and why. Add a section to your contributing guide explaining the linting configuration.
Practice Questions
1. What is the difference between Vale and markdownlint?
Vale lints prose style (word choice, tone, terminology). markdownlint lints Markdown formatting (heading structure, spacing, list syntax).
2. How does Vale know which rules to apply?
Vale reads a .vale.ini configuration file that specifies which style packages to use and which file formats to lint.
3. What happens when a linter finds a violation in CI?
The linter returns a non-zero exit code, which causes the CI pipeline to fail and blocks the Pull Request from merging.
4. Can you disable a linting rule for a specific line?
Yes. Vale supports inline comments: <!-- vale off --> and <!-- vale on -->. markdownlint supports <!-- markdownlint-disable -->.
5. Challenge: Create a custom Vale style for your project with five terminology substitutions. Configure markdownlint with a custom rule set. Create a GitHub Actions workflow that runs both linters on every PR.
FAQ
Mini Project
Set up a documentation Repository with a .vale.ini configuration using the Google style guide, a .markdownlint.json with 10 custom rules, and a CI workflow that runs both linters on every pull request.
What's Next
Linting covers style and formatting. Next, learn about Spell Check to catch typos and misspellings. Then explore Link Checking to prevent broken references.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro