Keep Markdown Consistent: Linting and Formatting Your Files
Quick answer
Markdown files drift out of sync with each other because Markdown itself doesn't enforce one style — the same heading, list, or line break can be written several valid ways. A linter like markdownlint fixes that by checking every file against a shared rule set: one heading style, consistent list indentation, no trailing whitespace, a sane line length. Below: why the drift happens, which rules to lock in first, and how to fold linting into a workflow you'll actually keep using.
Why Markdown formatting drifts in the first place
Markdown was designed to be readable as plain text, not to dictate one correct way to write it. John Gruber's original 2004 spec described a syntax, not a style guide. Over the following decade, editors and platforms implemented that syntax differently enough that the same document could render one way in one tool and another way somewhere else. CommonMark exists to close that gap — a strongly defined specification with a test suite, adopted by GitHub, GitLab, and Discord, so parsing behavior is at least predictable.
But CommonMark standardizes how Markdown is parsed, not how you write it. Nothing stops one file from using # headings while another uses underlined ones, or one list indenting two spaces while another uses four. Each choice renders fine on its own. The problem shows up once you have a few dozen files: mixed heading styles break outline and table-of-contents tools, inconsistent list indentation misaligns nested items, and trailing whitespace creates diffs that look like real changes when nothing meaningful moved.
Pick one heading style and stick to it
Headings are the highest-value place to standardize. A broken heading style breaks navigation, not just appearance. markdownlint's MD003 rule flags a document that mixes ATX-style headings (# Heading) with underlined setext headings — pick one and the rule holds you to it. ATX is the easier default: a single line, it works at any heading level from # through ######, and it's what most Markdown-aware tools expect when outlining a long document so its headings stay navigable.
Spacing matters too. MD018 and MD019 flag a missing or doubled space after the # characters — a small thing, but it's exactly the kind of inconsistency that stays invisible until a linter points at it. And structurally, a document should have one H1 as its title, with body content starting at H2. On a site that renders the page title separately, that means your Markdown body should never emit its own H1 at all.
Linting catches what code review misses
markdownlint checks more than headings: list markers and indentation (MD005, MD007), trailing whitespace and hard tabs (MD009, MD010), configurable line length (MD013), and link, image, and code-fence syntax. Trailing whitespace is the clearest example of why a linter earns its keep. An extra space at the end of a line is invisible in a normal read-through, but it shows up as a change in every diff. A human reviewer skims past it every time; a linter never does.
None of this requires heavyweight tooling. The VS Code extension surfaces issues inline while you type, markdownlint-cli2 runs the same checks from the command line, and a pre-commit hook catches drift before it reaches a shared repository. For a personal notes folder, running the CLI once before you publish is enough to catch the rules that matter.
Borrow a style guide instead of inventing one
You don't need to invent formatting conventions from scratch. Google's public Markdown style guide is a reasonable, permissive default: ATX headings only, an 80-character soft line limit with exceptions for links, tables, and code blocks, "lazy" list numbering (repeating 1. for every item so reordering doesn't require renumbering), and no trailing whitespace — line breaks use a trailing backslash instead. Google's own reasoning is telling: these choices are optimized for a document that many people edit over time. That's exactly the situation a growing set of notes or docs ends up in.
The specific choices matter less than picking one. A documented convention gives you something concrete to lint against. Without it, "consistent" formatting is just whatever the last person who touched the file happened to prefer.
The other formatting choices worth standardizing
A few more spots are worth locking in once headings are settled:
- List markers and indentation — pick one unordered-list marker (
-is the most common default) and a fixed indent width for nested items, so MD005/MD007 stay quiet. - Link style — decide between inline links and reference-style links up front; mixing both in the same file makes long documents harder to scan. See inline vs. reference-style links for the trade-offs.
- Escaping special characters — a consistent approach to escaping special characters with a backslash keeps tables and inline code from breaking when they contain a literal
*,_, or|. - Blockquotes and callouts — decide how deep nested blockquotes and callouts are allowed to go before a document gets hard to follow.
- GitHub Flavored Markdown extras — task lists, tables, and footnotes are a superset of CommonMark, so using them consistently doesn't cost portability as long as your renderer supports GFM.
Doing This with Carets
Carets is a fast, native Markdown, plain text, and code editor for iPhone, iPad, and Mac, and formatting consistency is easier to maintain when the editor doesn't fight you on it. Files, projects, and tags keep related notes organized in one place, so drift is easier to spot before it spreads across scattered files, and syntax highlighting makes a malformed heading or code fence obvious at a glance.
Carets won't replace a dedicated linter for a large shared repository — that's still a job for markdownlint-cli2 or a pre-commit hook. But for day-to-day writing and quick edits, a native editor that treats Markdown and code as first-class citizens makes it easier to catch inconsistency while you're writing, not weeks later. Carets is available now on the App Store for iPhone, iPad, and Mac.
Frequently Asked Questions
What is markdownlint and do I need it for personal notes?
markdownlint is a static-analysis tool that checks Markdown files against a configurable set of rules — heading style, list indentation, trailing whitespace, line length, and more. For a personal notes vault it's optional. But it's worth running periodically, or wiring into a save hook, once your file count grows past a few dozen and small inconsistencies start making files harder to scan or diff.
Should I follow CommonMark or GitHub Flavored Markdown?
Use GitHub Flavored Markdown if you want task lists, tables, and footnotes — it's a superset of CommonMark, so anything valid in plain CommonMark still works. The important thing isn't which spec you pick. It's picking one and writing to it consistently, since that's what keeps files portable across editors and renderers.
What's the single highest-value formatting rule to enforce first?
Heading style consistency. Mixing ATX and setext headings, or inconsistent heading levels, breaks document outlines and table-of-contents generation faster than almost any other inconsistency — and it's the easiest one to fix with a find-and-replace pass or a linter's autofix option.
Can I just format-on-save instead of running a linter?
Format-on-save handles whitespace and indentation in the file you're actively editing, but it won't catch drift across files you aren't currently touching. A periodic lint pass — even just before publishing or committing — catches the accumulated inconsistency that format-on-save alone misses.
Conclusion
Markdown's lack of a single mandatory style is exactly why formatting drifts across a growing set of files — and why a small, enforced set of rules matters more than it seems. Pick one heading style, one list convention, and clean whitespace, then let a linter check those rules instead of relying on memory. Once the basics are locked in, linting stops being a chore. It becomes a five-second check before you publish.