CLI tool
DavidAnson/vscode-markdownlint avatar
DavidAnson/vscode-markdownlint

vscode-markdownlint: Markdown style checking inside the editor

Markdown linting and style checking for Visual Studio Code

1,297 stars258 forksJavaScriptMIT

At a glance

What is it?
The markdownlint extension for Visual Studio Code reports Markdown style violations as you type, using the same markdownlint-cli2 engine that the command line tool and the GitHub Action use. It is a thin, well tested front end over a rule library, and the interesting decisions live in the engine, the configuration schema and the rules themselves.
Who is it for?
Adopt vscode-markdownlint if your team writes Markdown in VS Code and wants style problems surfaced while editing rather than in a review comment, and if you are prepared to configure the rules rather than accept the defaults. Do not adopt it as your only enforcement point, because the editor extension covers only the files a given developer opens.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 41 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Markdown flexibility is the reason a linter exists

The extension's introduction explains the problem in the project's own terms. The Markdown markup language is designed to be easy to read, write and understand, and it succeeds, but its flexibility is both a benefit and a drawback: many styles are possible, so formatting can be inconsistent.

The second half of the problem is compatibility. Some constructs do not work well in all parsers and should be avoided, and the README links a set of common and troublesome Markdown constructs as a starting point for reading about it. The result is that a document can look correct to the person who wrote it and render differently elsewhere, and nobody notices until a pull request review or a broken page.

markdownlint is the extension that brings a library of rules to Visual Studio Code, to encourage standards and consistency for Markdown files. The audience is a developer or technical writer who wants the feedback while typing rather than after committing, and the team that wants the same rules applied to everyone.

The project is MIT licensed, the repository is not archived, and the last push was on 2026-09-12. The extension version in package.json is 0.62.1, and the repository has no GitHub releases, so the marketplace listing and the version field are the record of what has shipped rather than a tag list.

A thin front end over the markdownlint-cli2 engine

The architecture is worth understanding because it tells you where the behaviour lives and where the limits are.

The extension is powered by the markdownlint library for Node.js, which was itself inspired by markdownlint for Ruby. The linting itself is performed by the markdownlint-cli2 engine. That is the important structural fact: the editor extension and the command line tool are two front ends over one engine.

The consequences are practical. The same rule set applies whether a developer sees a squiggle in the editor or a failure in a pipeline, so a warning in the editor and a CI failure are the same finding. And the engine is where a rule is implemented, tested and documented, so the extension's own repository is not where the rules live.

The README also points at a third front end, the markdownlint-cli2-action GitHub Action, which uses the same engine and can be integrated into project workflows. The README has an interoperability section for this, and the recommended arrangement is to use the extension while editing and the Action or the command line in continuous integration, so that the check does not depend on whether a given developer installed an extension.

The repository layout reflects the extension side of that split. There is a webworker/ directory, which is where the linting runs so that a long document does not block the editor, extension.mjs as the entry point, webpack.config.js for the bundle, and a test/ directory and a test-ui/ directory for the two kinds of testing.

Three installation routes, one of them scriptable

The install section gives three ways to get the extension, which is thorough for something that takes effect the moment it is enabled.

The first is the Quick Open dialog, opened with Ctrl+P on Windows and Linux or the command key on macOS, where you type ext install markdownlint to find the extension and then click Install and Enable.

The second is the Extensions tab, opened with Ctrl+Shift+X or the shift and command keys on macOS, where you type markdownlint instead.

The third is a command line prompt, and this is the one worth remembering because it is the only one you can put in a setup script:

bash
code --install-extension DavidAnson.vscode-markdownlint

The extension identifier in that command is DavidAnson.vscode-markdownlint, which is the publisher name and the repository name joined, while the name you see in the marketplace listing is simply markdownlint. The package.json records the same pairing, with name set to vscode-markdownlint and displayName set to markdownlint, which is why the two strings differ in the command and in the search box.

The extension is published through the Visual Studio Code marketplace, and the marketplace listing is the homepage recorded in the repository metadata.

Green squiggles, MD### codes and the quick fix dialog

The behaviour once installed is described in enough detail to be a manual.

When you edit a Markdown file, any line that violates a rule triggers a Warning in the editor, indicated by a wavy green underline. Green rather than red is a deliberate choice in the VS Code problem model, and the practical effect is that markdownlint findings read as advisory in the same gutter as other warnings.

The warnings panel opens with Ctrl+Shift+M, and hovering over a green line shows the warning. You can also cycle through them with F8 and Shift+F8, and every markdownlint warning begins with MD###, so the code itself tells you which rule fired.

The rule documentation is one click away. Placing the cursor on a line and clicking the light bulb icon, or pressing Ctrl+. or the command key with a period, opens the quick fix dialog, and clicking one of the warnings in that dialog displays that rule's help entry in your default web browser. That last point is what makes the rule identifiers useful rather than opaque: MD013 means something specific, and the documentation for it opens without leaving the editor.

The rules themselves are listed in the README with their identifiers, their names and one line descriptions, and each links to a documentation file in the markdownlint repository pinned at the v0.41.1 tag.

Which files get linted is a language mode decision

By default the extension scans and reports issues for files that VS Code treats as Markdown, and the README explains how to see and change that.

The language mode of the current file appears in the Status Bar at the bottom of the window, and VS Code's own documentation covers changing the language mode for the current file. That matters for a specific and common case: a Markdown file with a custom extension, or a template file, is not recognised as Markdown by default, so it is silently not linted.

The fix is to associate the file extension with the markdown language identifier, which the README also links. Once that association exists, the extension sees the file as Markdown and lints it like any other.

This is the mechanism behind the extension's main limitation, and it is a design boundary rather than a bug. A linter that runs inside the editor can only see what the editor opens and recognises, so a documentation set that is generated, or that lives in a format VS Code does not treat as Markdown, is outside its reach. The README also points to a tutorial by Dave Johnson, Build an Amazing Markdown Editor Using Visual Studio Code and Pandoc, for a longer walkthrough of the setup.

The rule list and where the configuration lives

The rules the extension enforces are the markdownlint library's rules, and the identifiers in the README give a clear picture of the coverage.

The heading family is the densest. MD001 heading-increment requires heading levels to increment by one level at a time, MD003 heading-style sets the heading style, MD022 blanks-around-headings requires blank lines around headings, MD023 heading-start-left requires headings to start at the beginning of the line, MD024 no-duplicate-heading flags repeated heading content, MD025 single-title or single-h1 catches multiple top level headings, and MD026 no-trailing-punctuation objects to punctuation in a heading. There is a family of spacing rules around ATX headings too, MD018 through MD021, covering a missing space after the hash, multiple spaces after the hash, a missing space inside the hashes and multiple spaces inside them.

Then come the whitespace and list rules. MD009 no-trailing-spaces, MD010 no-hard-tabs, MD012 no-multiple-blanks, MD005 list-indent for inconsistent indentation at the same level, MD007 ul-indent, MD004 ul-style, MD029 ol-prefix for ordered list numbering, MD027 and MD028 for blockquote spacing and blank lines, and MD011 no-reversed-links for link syntax written backwards.

Two rules are the ones teams usually have an opinion about. MD013 line-length imposes a line limit, and MD014 commands-show-output objects to dollar signs before commands when the output is not shown.

The configuration story is visible in the repository. There is a.markdownlint.json file at the root, which is the extension's own configuration for the repository's Markdown, and both markdownlint-config-schema.json and markdownlint-cli2-config-schema.json are checked in, with an embed-schema.cjs script that embeds the schema into the extension. Shipping a JSON schema is what gives editors completion and validation for the settings you write, and the presence of a schema-update script that pins the schema to a specific version of the upstream library shows the two are kept in step deliberately.

The build pipeline expects full coverage

The package manifest shows how the extension is developed and tested, and the numbers are the interesting part.

The test script runs the Node test runner with coverage enabled and three thresholds set to 100, covering branches, functions and lines, and then runs the lint task, the compile task and the schema copy task in sequence. The lint task is itself a compound command, running eslint over the project's own .cjs, .mjs and .js files and the test directories with a configuration file named eslint.config.mjs, and then running markdownlint-cli2 over the project's Markdown files. The extension is bundled with webpack, with a production mode script and a debug mode script that skips minification.

The repository therefore lints itself with the tool it ships, which is a reasonable self check, and the coverage thresholds mean a dropped branch fails the build rather than quietly reducing the number.

The schema tasks are the part that is unusual. schema-copy pulls the configuration schemas out of the installed markdownlint and markdownlint-cli2 packages and copies them into the repository root, schema-embed runs the embed script, and schema-update uses replace-in-files with a regular expression that rewrites the raw.githubusercontent.com URL for the upstream schema to a local path and strips the $id field. In other words, the extension ships a vendored copy of the upstream schema rather than fetching it at runtime, and there is a script to refresh that copy when the upstream library changes.

The alternative for a team that does not want an editor dependency is the engine itself, used from the command line or through the GitHub Action. The difference in approach is feedback timing and coverage. The extension reports while you type, in the file you have open, on your machine. The command line or Action reports on every commit, for every file, in a pipeline that runs whether or not anyone has the extension installed. The engine and the rules are identical in both cases, so the choice is about where the check runs, not about what it checks.

Editorial conclusion

Adopt vscode-markdownlint if your team writes Markdown in VS Code and wants style problems surfaced while editing rather than in a review comment, and if you are prepared to configure the rules rather than accept the defaults. Do not adopt it as your only enforcement point, because the editor extension covers only the files a given developer opens. Verify first that the rule set matches your house style, since MD013 line length and the heading rules in particular tend to need adjustment, confirm the configuration file you rely on is one the extension reads, and keep markdownlint-cli2 in CI so that the check does not depend on who has the extension installed.

Frequently asked questions

How do I install the markdownlint extension for VS Code?

You can use the Quick Open dialog and type ext install markdownlint, find it in the Extensions tab with Ctrl+Shift+X, or run code --install-extension DavidAnson.vscode-markdownlint from a command line prompt. The extension identifier differs from the displayed name, which is simply markdownlint.

Why are some Markdown files not linted by the extension?

By default the extension scans the files that VS Code treats as Markdown, and the language mode of the current file is shown in the Status Bar. If a custom file type should always be treated as Markdown, you can associate that file extension with the markdown language identifier.

How do I see the documentation for a markdownlint rule?

Place the cursor on the offending line and open the quick fix dialog with Ctrl+. or the command key and a period, then click one of the warnings to display that rule's help entry in your default web browser. Every markdownlint warning begins with MD### so the identifier points to the rule.

Can I run the same Markdown checks in CI?

Yes. The extension is powered by the markdownlint-cli2 engine, and the README points at the markdownlint-cli2-action GitHub Action which uses the same engine, so the same rules apply in a pipeline as in the editor.

Official sources

  1. DavidAnson/vscode-markdownlint on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/davidanson-vscode-markdownlint.svg)](https://hysenlabs.com/projects/davidanson-vscode-markdownlint)

Was this useful?