Skip to content
Last updated

Markdown rules

Markdown rules check the structure and formatting of a file: headings, lists, links, images, tables, code fences, and whitespace. Recheck ports every built-in markdownlint rule and adds a few of its own. The recheck/markdown preset turns the 53 ported rules on at error.

A Markdown rule is configured under its key in the recheck block. The key of a preset rule is recheck/<rule>, and the rule's options go under the assertion of the same name:

extends:
  - recheck/markdown
recheck:
  rules:
    recheck/line-length:
      severity: warn
      assertions:
        line-length:
          lineLength: 120
          codeBlocks: false
    recheck/ul-style: off

A rule that is not in any preset is added the same way. The message is optional for a Markdown rule, because each rule has its own:

recheck:
  rules:
    recheck/list-length:
      severity: warn
      assertions:
        list-length:
          min: 2
          max: 10

Rules in the markdown preset

The table lists each rule with its markdownlint id and whether --fix can repair it. Options are listed after the table.

Document headings

RulemarkdownlintFixableChecks
heading-incrementMD001NoHeading levels increase by one level at a time.
heading-styleMD003NoOne heading style (ATX, closed ATX, or setext) across the file.
no-missing-space-atxMD018YesA space after the # of a heading.
no-multiple-space-atxMD019YesOne space after the # of a heading.
no-missing-space-closed-atxMD020YesSpaces inside the hashes of a closed ATX heading.
no-multiple-space-closed-atxMD021YesOne space inside the hashes of a closed ATX heading.
blanks-around-headingsMD022YesBlank lines around headings.
heading-start-leftMD023YesHeadings start at the beginning of the line.
no-duplicate-headingMD024NoNo two headings with the same text.
single-h1MD025NoOne top-level heading per file. Alias: single-title.
no-trailing-punctuationMD026YesNo trailing punctuation in a heading.
no-emphasis-as-headingMD036NoEmphasis is not used in place of a heading.
first-line-h1MD041NoThe first line of the file is a top-level heading. Alias: first-line-heading.
required-headingsMD043NoThe file follows a required heading structure.

Whitespace and lines

RulemarkdownlintFixableChecks
no-trailing-spacesMD009YesNo trailing spaces at the end of a line.
no-hard-tabsMD010YesNo hard tabs.
no-multiple-blanksMD012YesNo consecutive blank lines.
line-lengthMD013NoLines stay within a length.
single-trailing-newlineMD047YesThe file ends with one newline.
hr-styleMD035NoOne horizontal rule style across the file.

Lists

RulemarkdownlintFixableChecks
ul-styleMD004YesOne bullet style (-, *, or +) for unordered lists.
list-indentMD005YesItems at the same level share the same indentation.
ul-indentMD007YesNested unordered lists indent by a fixed width.
ol-prefixMD029YesOrdered list numbers follow one style.
list-marker-spaceMD030YesA fixed number of spaces after a list marker.
blanks-around-listsMD032YesBlank lines around lists.

Code

RulemarkdownlintFixableChecks
commands-show-outputMD014YesNo $ before a shell command unless the output is shown too.
blanks-around-fencesMD031YesBlank lines around fenced code blocks.
no-space-in-codeMD038YesNo spaces inside inline code spans.
fenced-code-languageMD040NoEvery fenced code block names a language.
code-block-styleMD046NoOne code block style (fenced or indented) across the file.
code-fence-styleMD048NoOne fence style (backticks or tildes) across the file.
RulemarkdownlintFixableChecks
no-reversed-linksMD011YesLink syntax is not reversed, as in (text)[url].
no-space-in-linksMD039YesNo spaces inside link text.
no-empty-linksMD042NoEvery link has a destination.
no-bare-urlsMD034YesURLs are wrapped in angle brackets or a link.
no-alt-textMD045NoEvery image has alt text.
link-fragmentsMD051Yes#fragment links point at a heading or anchor that exists.
reference-links-imagesMD052NoReference links and images use a label that is defined.
link-image-reference-definitionsMD053YesEvery reference definition is used.
link-image-styleMD054YesOnly the allowed link and image styles are used.
descriptive-link-textMD059NoLink text is descriptive, not "click here" or "more".

Emphasis and inline

RulemarkdownlintFixableChecks
no-space-in-emphasisMD037YesNo spaces inside emphasis markers.
no-inline-htmlMD033NoNo inline HTML.
proper-namesMD044YesListed names use the configured capitalization.
emphasis-styleMD049YesOne emphasis style (* or _) across the file.
strong-styleMD050YesOne strong style (** or __) across the file.

Blockquotes and tables

RulemarkdownlintFixableChecks
no-multiple-space-blockquoteMD027YesOne space after the > of a blockquote.
no-blanks-blockquoteMD028NoNo blank line inside a blockquote.
table-pipe-styleMD055NoOne table pipe style across the file.
table-column-countMD056NoEvery table row has the same number of columns.
blanks-around-tablesMD058YesBlank lines around tables.
table-column-styleMD060YesTable columns follow one alignment style.

Rules outside the presets

These rules have no markdownlint counterpart and no preset turns them on. Add them to the recheck block by name.

RuleFixableChecks
front-matterNoFront matter matches a JSON Schema. See Front matter.
list-lengthNoA list has at least min items (default 2) and at most max items (no default). Nested lists count on their own.
no-empty-headingsNoA heading has text content. Inline code counts as content.
no-duplicate-link-destinationsNoThe same destination is not linked with different text in one file. Repeating the same text for the same destination is fine.

The four Markdoc rules are documented with the recheck/markdoc preset.

Options

Options go under the assertion with the rule's name. A rule not listed here has no options. An option name a rule does not recognize is ignored without a warning.

blanks-around-fences

OptionTypeDefaultDescription
listItemsbooleantrueAlso require blank lines around fences inside list items.

blanks-around-headings

OptionTypeDefaultDescription
linesAbovenumber1Blank lines required above a heading.
linesBelownumber1Blank lines required below a heading.
includeFrontMatterbooleanfalseRequire a blank line between front matter and a heading.

code-block-style, code-fence-style, emphasis-style, heading-style, hr-style, strong-style, table-pipe-style, ul-style

OptionTypeDefaultDescription
stylestringconsistentconsistent uses the first style found in the file. The other values name one style, for example fenced, backtick, asterisk, underscore, atx, dash, leading_and_trailing, or sublist.

The accepted names match markdownlint's options for the rule with the same id.

OptionTypeDefaultDescription
prohibitedTexts[string]['click here', 'here', 'link', 'more']Link texts that are reported.

fenced-code-language

OptionTypeDefaultDescription
allowedLanguages[string][]When set, only these languages are allowed.
languageOnlybooleanfalseReport an info string that carries more than the language.

first-line-h1, single-h1, heading-increment

OptionTypeDefaultDescription
frontMatterTitlestring^\s*"?title"?\s*[:=]A regex. Front matter that matches it counts as the top-level heading. Set '' to ignore front matter.
levelnumber1first-line-h1 and single-h1 only: the heading level that counts as the title.
allowPreamblebooleanfalsefirst-line-h1 only: allow content before the first heading.

line-length

OptionTypeDefaultDescription
lineLengthnumber80Maximum line length.
headingLineLengthnumberMaximum length of heading lines. Falls back to lineLength.
codeBlockLineLengthnumberMaximum length of lines in code blocks. Falls back to lineLength.
codeBlocksbooleantrueCheck code blocks.
tablesbooleantrueCheck tables.
headingsbooleantrueCheck headings.
strictbooleanfalseReport long lines even when they hold no whitespace to break at.
sternbooleanfalseReport long lines that could be broken, allow the rest.
OptionTypeDefaultDescription
ignoreCasebooleanfalseMatch fragments without regard to case.
ignoredPatternstring''A regex. Fragments that match it are not checked.
crossFilebooleanfalseAlso check links and images to other files. See Cross-file links.
rootDirstring or object''With crossFile, the folder that site-root links such as /guides/intro resolve against. An object maps a source folder prefix to its root for monorepos; the longest matching prefix wins.
ignoredTargets[string][]With crossFile, destination globs that are not checked, for routes a site generates from data.

With crossFile: true, the rule replaces an external link checker for links inside the repository:

  • A relative link or image target must exist on disk.
  • A file.md#anchor fragment must exist in the target file's headings and anchors.
  • Extensionless links resolve the way the Realm router does: ./page tries page.md, and a folder link reads its index.md.
  • Site-root links such as /x/y resolve against rootDir, and are skipped without it.
  • Links to <details> sections resolve, with the id derived from the <summary> text when none is set.
  • Markdoc tags in a heading do not change its anchor.
  • External URLs and mailto: links are skipped.
recheck:
  rules:
    recheck/link-fragments:
      severity: error
      assertions:
        link-fragments:
          crossFile: true
          rootDir: docs
          ignoredTargets:
            - '/gateways/**'
OptionTypeDefaultDescription
ignoredDefinitions[string]['//']Definition labels that may stay unused.
OptionTypeDefaultDescription
autolinkbooleantrueAllow <https://example.com>.
inlinebooleantrueAllow [text](url).
fullbooleantrueAllow [text][label].
collapsedbooleantrueAllow [label][].
shortcutbooleantrueAllow [label].
urlInlinebooleantrueAllow [https://example.com](https://example.com).

list-length

OptionTypeDefaultDescription
minnumber2Minimum number of items in a list.
maxnumberMaximum number of items in a list.

list-marker-space

OptionTypeDefaultDescription
ulSinglenumber1Spaces after a bullet in a list of single-line items.
olSinglenumber1Spaces after a number in a list of single-line items.
ulMultinumber1Spaces after a bullet in a list with multi-line items.
olMultinumber1Spaces after a number in a list with multi-line items.

no-duplicate-heading

OptionTypeDefaultDescription
siblingsOnlybooleanfalseReport duplicates only among headings with the same parent.
respectSectionsbooleanfalseReport duplicates only inside the same section. A Recheck extension.
caseSensitivebooleantrueCompare heading text with regard to case. A Recheck extension.
ignoreCommonHeadingsbooleanfalseSkip common headings such as "Overview", "Examples", and "Troubleshooting". A Recheck extension.

no-emphasis-as-heading, no-trailing-punctuation

OptionTypeDefaultDescription
punctuationstring.,;:!?。,;:!? for no-emphasis-as-heading, the same without ? and ? for no-trailing-punctuationThe characters that count as punctuation.

no-hard-tabs

OptionTypeDefaultDescription
codeBlocksbooleantrueCheck code blocks.
ignoreCodeLanguages[string][]Code block languages that may contain tabs.
spacesPerTabnumber1Spaces that replace each tab with --fix.

no-inline-html

OptionTypeDefaultDescription
allowedElements[string][]HTML elements that are allowed.
tableAllowedElements[string][]HTML elements that are allowed inside tables.

no-multiple-blanks

OptionTypeDefaultDescription
maximumnumber1Consecutive blank lines allowed.

no-multiple-space-blockquote

OptionTypeDefaultDescription
listItemsbooleantrueAlso check list items inside blockquotes.

no-trailing-spaces

OptionTypeDefaultDescription
brSpacesnumber2Trailing spaces that count as a hard line break and are allowed.
codeBlocksbooleanfalseCheck code blocks.
listItemEmptyLinesbooleanfalseAllow trailing spaces on empty lines inside list items.
strictbooleanfalseReport every trailing space, including hard line breaks.

ol-prefix

OptionTypeDefaultDescription
stylestringone_or_orderedone, ordered, one_or_ordered, or zero.

proper-names

OptionTypeDefaultDescription
names[string][]Names with their correct capitalization.
codeBlocksbooleantrueCheck code blocks.
htmlElementsbooleantrueCheck HTML elements.
OptionTypeDefaultDescription
shortcutSyntaxbooleanfalseAlso check shortcut references such as [label].
ignoredLabels[string]['x']Labels that are not checked.

required-headings

OptionTypeDefaultDescription
headings[string]The required headings in order. * matches zero or more headings, + one or more, and ? zero or one.
matchCasebooleanfalseCompare heading text with regard to case.

table-column-style

OptionTypeDefaultDescription
stylestringanyany, aligned, compact, or tight.
alignedDelimiterbooleanfalseRequire the delimiter row to be aligned with the columns.

ul-indent

OptionTypeDefaultDescription
indentnumber2Spaces per nesting level.
startIndentedbooleanfalseAllow the first level to be indented.
startIndentnumber2Spaces of indentation for the first level when startIndented is on.

Front matter

The front-matter rule validates front matter against a JSON Schema with the same validator that Redocly CLI uses for API descriptions. Map file globs to schemas. The first mapping that matches a file wins, and a file that matches no mapping is not checked.

recheck:
  rules:
    recheck/front-matter:
      severity: error
      assertions:
        front-matter:
          schemas:
            - files: ['.changeset/**']
              schema:
                type: object
                patternProperties:
                  '^@redocly/': { enum: [major, minor, patch] }
                additionalProperties: false
            - files: ['docs/**']
              schema: realm
              strict: true

Each mapping takes these keys:

KeyTypeDescription
files[string]File globs the mapping applies to.
schemaobject or stringAn inline JSON Schema, or the name of a built-in schema. realm is the only built-in schema.
schemaFilestringPath to a YAML or JSON schema file, relative to the working directory. Used when schema is not set.
strictbooleanReport keys the schema does not define. Default false.

A file with no front matter validates as an empty object, so the schema's required list decides whether front matter is mandatory. Each finding points at the line of the offending top-level key. Front matter that is not valid YAML is one finding at the start of the block.

The built-in realm schema checks the type of every front matter option that a Realm page accepts, such as title, description, slug, sidebar, excludeFromSearch, and the options that override redocly.yaml on one page. It does not check the inner shape of those option objects, because Realm evolves them independently. strict is off by default, because pages often carry their own keys that Markdoc templates read back through $frontmatter.