Skip to content

MD013 - Keep lines short for better readability

Aliases: line-length

What this rule does

Checks that lines don't exceed a maximum length to ensure your content is easy to read on all devices.

Why this matters

  • Improves readability: Shorter lines are easier to scan and understand quickly
  • Works everywhere: Content displays properly on mobile devices, terminals, and narrow windows
  • Better for code reviews: Side-by-side comparisons work better with reasonable line lengths
  • Accessibility: Screen readers and assistive technologies handle shorter lines more effectively

Examples

✅ Correct

This line is a reasonable length that's easy to read
and displays well on all devices.

Even with links, you can keep lines manageable by using
[reference-style links][1] instead of inline URLs.

[1]: https://example.com/very-long-url-that-would-make-the-line-too-long

❌ Incorrect

This is an extremely long line that goes on and on and makes it difficult to read the content, especially on mobile devices or when viewing files in split-screen editors or during code reviews where horizontal space is limited.

🔧 Fixed

This is a line that has been wrapped to stay within
the maximum length, making it much easier to read
and work with in various contexts.

Configuration

[MD013]
line-length = 100  # Maximum characters per line (default: 80)
code-blocks = false  # Don't check code blocks (default: true)
code-spans = false  # Don't flag lines whose only overflow is an unbreakable inline code span (default: true)
tables = false  # Don't check tables (default: false)
headings = true  # Check headings (default: true)
math-blocks = false  # Don't check display-math blocks (default: true)
bracket-display-math = false  # Protect standalone \[ ... \] TeX display math (default: false)
paragraphs = true  # Check paragraph/regular text (default: true)
blockquotes = true  # Check blockquote content (default: true)
strict = false  # Disables exceptions for URLs, etc. (default: false)
stern = false  # Like strict, but unwrappable single-token lines are still permitted (default: false)
ignore-link-urls = true  # Ignore inline link/image URLs when measuring line length (default: true)
heading-line-length = 100  # Optional per-context limit for headings; falls back to line-length when unset
code-block-line-length = 120  # Optional per-context limit for code blocks; falls back to line-length when unset
reflow = false  # Enable automatic text reflow/wrapping (default: false)
reflow-mode = "default"  # "default", "normalize", "sentence-per-line", "sentence-pack", or "semantic-line-breaks"
length-mode = "visual"  # How to count line length: "visual", "chars", or "bytes" (default: "visual")
abbreviations = ["Assn", "Univ"]  # Add custom abbreviations for sentence-driven reflow modes
link-text-punctuation = "ignore"  # "trailing" considers terminal link text and image alt punctuation
break-words = ["puisque", "porque"]  # Add semantic break words for your project's prose
require-sentence-capital = true  # Require uppercase to start the next sentence (default: true)
atomic-spans = true  # Treat code/emphasis spans as atomic units during reflow (default: true)
reflow-break-link-text = false  # Allow reflow to wrap long lines within link/image text (default: false)
reflow-break-code-spans = true  # Allow word-by-word reflow within inline code when atomic-spans is false (default: true)
reflow-length-exemptions = false  # Measure reflowed lines with the same exemptions the check applies (default: false)
cjk-soft-break = "space"  # How reflow joins a line break between two CJK characters: "space" or "join" (default: "space")

Configuration options explained

  • line-length: The maximum number of characters allowed per line (set to 0 to disable all line length checks)
  • code-blocks: Whether to check line length in code blocks (default: true)
  • code-spans: Whether to check lines whose length comes from an inline code span (default: true). Inline code spans (`like this`) cannot be wrapped, so reflow cannot shorten a line whose excess length is one. When false, a line is not reported if it would fit within the limit once its inline code spans are excluded - useful with reflow so an unbreakable code incantation does not fail an otherwise-clean file
  • tables: Whether to check line length in tables (default: false)
  • headings: Whether to check line length in headings (default: true)
  • math-blocks: Whether to check line length in display-math blocks (default: true). A $$ ... $$ block is unbreakable in the same way a code block or a table row is: LaTeX cannot be wrapped without changing the equation. When false, lines that hold nothing but display math are not reported, covering both a multi-line block and a whole line that is one complete $$...$$ span, delimiter lines included (as code-blocks = false also exempts the surrounding fences). A delimiter line that also carries Markdown ($$ trailing prose, leading prose $$) is still measured, since that prose is ordinary text. Inline $...$ math is not covered, for the same reason code-spans is a separate option from code-blocks. Like the other block flags, this has no effect under strict. Independently of this setting, reflow never rewrites a multi-line display-math block, because a TeX % comment runs to the end of its line and joining lines would pull later rows into the comment
  • bracket-display-math: Recognize standalone TeX \[ ... \] blocks as display math (default: false). Enable this only for a renderer that treats those delimiters as math. A matched multi-line block keeps its authored line breaks during reflow, including inside lists and blockquotes; a complete \[ ... \] line stays separate from adjacent prose. An unmatched opener is ordinary Markdown. With this option on, math-blocks = false also exempts recognized bracket display math from the width check. With it off, escaped brackets keep their normal CommonMark meaning.
  • paragraphs: Whether to check line length in regular text/paragraphs (default: true). When false, line-length is still used for reflow but no warnings are reported. Blockquote content is treated as paragraph text, so paragraphs = false also skips blockquotes
  • blockquotes: Whether to check line length in blockquote content (default: true). Set to false to skip blockquote lines specifically without disabling all paragraph checks
  • strict: When true, disables exceptions for URLs and other special content (default: false). Overrides stern.
  • stern: Tighter than the default but laxer than strict. Disables the trailing-token forgiveness used in default mode (so a line is flagged even when only the final token spills past the limit), but keeps the "unwrappable line" exemption — lines that consist of a single non-whitespace token, optionally prefixed by # heading or > blockquote markers, are still permitted (default: false). Mirrors markdownlint's stern option.
  • ignore-link-urls: Whether to forgive a line that exceeds the limit only because of the URL inside an inline [text](url) / ![alt](url) (default: true; see Ignoring inline link URLs). Set to false to count those URLs toward the line length. Combined with stern, this flags a link line that has wrappable text around it while still exempting a line that is a single unbreakable token (a bare URL or a standalone link): stricter than stern about links, but without strict flagging genuinely unbreakable link lines. Has no effect under strict (which already disables all forgiveness). The former key semantic-link-understanding is still accepted as an alias.
  • heading-line-length: Per-context maximum length for heading lines. Unset (null) falls back to line-length; 0 means "no limit for headings". Mirrors markdownlint's heading_line_length option.
  • code-block-line-length: Per-context maximum length for fenced or indented code-block lines. Unset (null) falls back to line-length; 0 means "no limit for code blocks". Mirrors markdownlint's code_block_line_length option.
  • reflow: When true, enables automatic text reflow to wrap long lines intelligently (default: false)
  • reflow-mode: Controls how text is reflowed when reflow is true (default: "default", see Reflow Modes section below)
  • length-mode: How to calculate line length (default: "visual"):
  • "visual": Count visual display width (emoji = 2 columns, CJK = 2 columns). Recommended and default. Correctly handles international content and matches terminal display.
  • "chars": Count Unicode characters (emoji = 1, CJK = 1). Use only for backward compatibility.
  • "bytes": Count raw UTF-8 bytes (not recommended for Unicode text).
  • abbreviations: Custom abbreviations for sentence-driven reflow modes (optional)
  • Periods are optional: both "Dr" and "Dr." work the same
  • Added to built-in defaults: Mr, Mrs, Ms, Dr, Prof, Sr, Jr, i.e, e.g, vs, fig, no, vol, ch, sec, al
  • link-text-punctuation: Whether sentence detection considers punctuation at the end of link text or image alt text (default: "ignore"). Set "trailing" to opt in; the complete link or image stays together. See Sentence endings in links and images. Also accepts link_text_punctuation.
  • break-words: Additional words that can begin a new line in semantic-line-breaks mode (default: [])
  • Extends the built-in English break words
  • Matches whole words case-insensitively, including Unicode, and preserves their spelling in the output
  • Use a single word per entry; empty entries have no effect
  • Also accepts the key break_words
  • require-sentence-capital: Whether a sentence boundary requires the next sentence to start with an uppercase letter (default: true)
  • When true, only word. Capital is treated as a sentence boundary (fewer false positives). A digit counts as opening a sentence too, since a lowercase continuation is what the setting guards against: The count was 5. 2 of them failed. and Released in 2020. 3rd edition. split, See fig. 3 and The count was 5. and that was all do not
  • When false, word. lowercase is also treated as a sentence boundary (more splitting)
  • In sentence-per-line mode, an existing line break after a sentence is preserved even when the next line starts with lowercase text or a reference link such as [#752]. Hard-wrapped continuations after abbreviations, initials, version numbers, or quoted phrases still join. The uppercase requirement continues to apply when the source has a space instead of a line break
  • A bare ! or ? is always a sentence boundary, since neither is ambiguous the way a period is (which also ends abbreviations, decimals and initials). Inside a quotation the setting does apply, because the question can belong to the quoted phrase rather than to the sentence carrying it: A "Is this a test?" guide stays one sentence
  • A code span opens a sentence whatever the setting: it starts on a delimiter rather than on a letter, and the case of what it holds belongs to the code, so Reads the file. `config.toml` holds the rest. is two sentences. The code span has to be one the parse recognises, since an unmatched backtick is ordinary text and the sentence carries on through it. Not after one mark of an elision, so Choose File... `Open Folder` appears in the menu. stays one, and not after a bare digit, so the enumeration Steps: 1. `init` the repo, 2. `build` it. and the version Pinned at 0.2.43. `rumdl` reads it. stay one too. A digit inside a span is a label's rather than an enumerator's, so **A2.** `UserProvider` re-mints the token. is two
  • atomic-spans: Whether to hold emphasis/strong/strikethrough and code spans atomic during reflow (default: true). When true, these spans are treated as atomic units. When false, they can be wrapped word-by-word like normal text. An emphasis/strong/strikethrough span that is on its own longer than line-length is wrapped even when atomic-spans is true, since holding it whole would leave a line that can never fit. Such a span wraps at whitespace outside any nested construct. A nested code span, link, image or HTML tag is never broken, since the whitespace inside one is literal (code) or structural (a link destination), so a line break there would rewrite the document. A nested emphasis, strong or strikethrough span does wrap: the whitespace inside it is ordinary prose whitespace, and only its delimiters are held to the words they flank. This is what lets a span whose entire content is another span, such as ***text***, wrap at all. A span containing a marker character that is not part of a well-formed nested span (a stray or backslash-escaped `, *, _ or ~) is kept atomic rather than broken on a guess. Code spans themselves are never broken while atomic-spans is true. When atomic-spans is false, code spans still stay intact in containers and indented paragraphs, where wrapping could insert literal whitespace into their content. To wrap emphasis word by word while keeping code spans whole, set atomic-spans = false and reflow-break-code-spans = false.
  • reflow-break-link-text: Whether reflow may wrap a long line within the text of a link or image (default: false). Off, every link and image is one atomic token: an overlong link moves whole to its own line, which the check exempts as a standalone link. On, the bracketed text of [text](url) wraps at whitespace under the same rules atomic-spans applies to emphasis spans: only when the whole construct is longer than line-length (or freely, when atomic-spans is false). The inline, full ([text][ref]), collapsed ([text][]) and shortcut ([text]) forms and the corresponding image forms all wrap alike; reference labels normalize internal whitespace, so a wrapped label still resolves. The ](...) tail is never split, and a link stays whole whenever splitting would produce a line the check reports but reflow cannot fix: when the destination alone exceeds the limit while the text fits (splitting could not shorten anything the URL exemption does not already forgive), or when the tail line's overflow would not be confined to its final token (for example a title pushed past the limit)
  • reflow-break-code-spans: Allow word-by-word reflow within inline code spans when atomic-spans is false (default: true). Set it to false to keep code spans whole while emphasis, strong and strikethrough still wrap. It has no effect while atomic-spans is true, which already holds code spans whole. The whitespace, container and indentation safeguards always apply. A code span longer than line-length stays whole on its own line, and the check reports that line under its usual rules (code-spans, strict, stern); the code-spans option is the length-check exemption for such lines, not a wrapping control
  • reflow-length-exemptions: Whether reflow measures a line with the same length exemptions the check applies (default: false). Off, reflow measures the markdown as written, so a paragraph whose only excess is an inline link destination is rewrapped even though the check forgives it. On, reflow consults ignore-link-urls (an inline [text](url) costs [text], ![alt](url) costs ![alt]) and code-spans (a code span costs nothing), and leaves such a paragraph alone. See Measuring reflowed lines the way the check measures them.
  • cjk-soft-break: How reflow joins two lines when the characters on both sides of the line break are Chinese or Japanese (default: "space"). "space" joins them with a space, like every other line break. "join" joins them with nothing, for renderers that drop the line break between CJK characters. See Joining CJK line breaks.

In non-strict mode, this rule understands that inline links and images often contain long URLs that the author cannot reasonably shorten. When a line exceeds the limit, the rule checks whether replacing each [text](url) with just [text] (and ![alt](url) with ![alt]) would bring the line within the limit. If so, the warning is suppressed.

This applies to:

  • Inline links: [text](url) and [text](url "title")
  • Inline images: ![alt](url)
  • Nested badge patterns: [![alt](img-url)](link-url)

This does not apply to:

  • Reference links ([text][ref]) — these already have no inline URL
  • Autolinks (<url>) — the URL itself is the visible content
  • Strict mode — all exceptions are disabled
  • Reflow, by default. ignore-link-urls decides whether a line is reported; on its own it does not change how reflow measures one. Reflow measures the markdown as written, including link destinations, so a paragraph whose only over-length cause is a link URL is still rewrapped and the link still lands on its own line. prettier (--prose-wrap always) and mdformat (--wrap) wrap such a paragraph the same way. stern and code-spans leave reflow alone in the same way. strict is the exception: it removes the standalone-link and HTML-line exemptions everywhere, including inside reflow, so it can make reflow report a paragraph that is otherwise left alone. The sentence-driven modes differ in the other direction: sentence-per-line, sentence-pack and semantic-line-breaks shape a paragraph by its sentences, so a link line that continues the prose above it is joined into that sentence instead of standing on its own. Set reflow-length-exemptions = true to have reflow honor this exemption, or reflow = false to keep those lines as authored.
  • ignore-link-urls = false: count inline link/image URLs toward the line length. With stern, this flags a link line that has wrappable text around it, while a line that is a single unbreakable token (a bare URL or a standalone link) is still permitted by stern's unwrappable-line exemption.

Measuring reflowed lines the way the check measures them

By default the two halves of MD013 measure differently. The check forgives a line whose only excess is an inline link destination or an inline code span; reflow measures every character it can see. On a paragraph like

The release notes for [the migration guide](https://example.com/docs/guides/migration/v3) explain it.

the check says nothing, and rumdl fmt still rewraps the paragraph so the link sits alone on a line that remains over the limit. Nothing is wrong with the result, but the formatter has rewritten a paragraph the linter never objected to.

reflow-length-exemptions = true makes reflow ask the same question the check asks. It reads no new options: ignore-link-urls and code-spans already describe which exemptions are in force, and reflow now consults exactly those. The paragraph above is left as authored, and a paragraph that is genuinely too long is wrapped as before.

The two exemptions stay independent, as they are in the check. A line is left alone when discounting link destinations brings it under the limit, or when discounting code spans does, never when only the two savings together would. What the option cannot produce is a line the check reports and reflow declines to wrap: reflow stays at least as willing to wrap as the check is to complain.

Only inline links and images are discounted. Reference ([text][ref]), collapsed and shortcut forms carry no destination and are measured in full, and a construct reflow cannot resolve is measured in full as well, so the setting never leaves behind a line the check would report.

Example

With line-length = 80:

<!-- No warning: text without URLs is only ~30 chars -->
See the [installation guide](https://example.com/docs/getting-started/installation/v2) for details.

<!-- Warning: text alone still exceeds 80 chars -->
This is already a very long sentence with lots of words that pushes past the limit even [without](https://example.com) the URL.

Joining CJK line breaks

CommonMark renders a line break inside a paragraph as a space. Chinese and Japanese are written without spaces between words, so CJK-aware renderers drop that space when both sides of the break are CJK text: for example markdown-it-cjk-breaks and Pandoc's east_asian_line_breaks extension. When reflow joins such lines it writes a space into the source, and that space is then rendered by every renderer.

cjk-soft-break = "join" makes reflow join those lines without a space:

[MD013]
reflow = true
reflow-mode = "sentence-per-line"
line-length = 0
cjk-soft-break = "join"
<!-- Before -->
这段测试
文字尚未结束。

<!-- After -->
这段测试文字尚未结束。

This changes the rendered text, so only enable it when you write CJK text that should read without spaces. The line break is joined without a space only when the characters directly on both sides of it are Han, Hiragana, Katakana or CJK punctuation such as 。, , and 「. Everything else keeps the space:

  • Korean, which separates words with spaces.
  • A break between CJK and other text (中文 and English).
  • Punctuation that Western text shares, such as “, … and —.
  • A break next to markup: emphasis, a link, a code span or an HTML tag. Removing the space can change how these parse: **「强调」** followed by a line break and 文字 is bold, but **「强调」**文字 is not.
  • A break inside a code span, where the space is part of the code.

Spaces the author typed are never removed; only the line break itself is.

The setting also decides where sentence-per-line and semantic-line-breaks start a new line after a CJK sentence ending (。, !, ?). A line break there must render the same as the text it replaces:

  • With the default space, a line break renders as a space, so sentences written without a space between them (文です。次の文です。) stay on one line. Sentences separated by a space are still put on separate lines.
  • With join, sentences written without a space between them are put on separate lines, and sentences separated by a space stay on one line when the characters on both sides of that space are joined.

With a line-length limit, a joined CJK run has no space left to wrap at, so a paragraph can end up on one line longer than the limit. The check does not report a line that has no space to wrap at, except under strict. sentence-pack is the exception to that exception: its width is deliberately soft, so an indivisible sentence or source-preserving sentence group may exceed it even when strict = true.

Automatic fixes

When reflow is set to true, this rule can automatically wrap long lines while preserving Markdown formatting:

  • Intelligently breaks lines at appropriate points
  • Preserves bold, italic, links, code spans, and other Markdown elements
  • Reflows list items using the configured marker spacing and aligns continuation lines to the content column (see List reflow and marker spacing)
  • Reflows blockquote paragraphs (including lazy continuation lines) while preserving input style
  • Reflows definition list definitions, indenting wrapped lines to the definition's text (see Definition list reflow)
  • Preserves hard line breaks (two trailing spaces)
  • Does not wrap code blocks, tables, headings, or reference definitions
  • Does not wrap a multi-line display-math block. A TeX % comment runs to the end of its line, so joining the lines would pull whatever followed on later lines into the comment and drop it from the rendered equation, possibly leaving an environment unclosed. Use math-blocks = false to also stop reporting the length of those lines

List reflow and marker spacing

When reflowing list items (including nested and blockquote-nested lists), rumdl does not hard-code the spacing after a list marker. In the spacing-normalizing modes (default and normalize) it derives the number of spaces after the marker from the MD030 configuration (ul-single/ul-multi for unordered lists, ol-single/ol-multi for ordered lists, and the ol-align-column override), choosing the single- or multi-line value the same way MD030 does. Continuation (wrapped) lines are then indented to the resulting content column, so wrapped text aligns under the item's text exactly as MD007's text-aligned style expects. Under the default MD030 setting a marker written with extra spaces (* item) is therefore rewritten to a single space.

Changing the spacing moves the item's content column, so reflow does it only when it rewrites every line the item holds. An item that contains a nested list or a nested blockquote keeps the marker spacing it was written with, and so does everything inside it; MD030 adjusts that spacing and moves the item's contents along with it. A lazy continuation line (one that continues the item's paragraph without being indented) is reflowed with the paragraph and indented under the item.

The sentence-per-line, sentence-pack and semantic-line-breaks modes only change where lines break, so they preserve the marker spacing and indentation already in the source. The MkDocs flavor keeps its own fixed 4-space structural indent.

Example (line-length = 50, MD030 ol-multi = 2):

# Before
1. This is a fairly long numbered item that wraps onto another line.

# After
1.  This is a fairly long numbered item that wraps
    onto another line.

Blockquote reflow style preservation

When reflowing blockquote paragraphs, rumdl preserves the source style:

  • Explicit continuation input stays explicit (> on wrapped lines)
  • Lazy continuation input stays lazy when safe
  • Mixed explicit/lazy input uses deterministic style selection (explicit on ties)
  • Lazy output is automatically upgraded to explicit for lines that would otherwise start a new block structure

Example (line-length = 60):

# Before
> This is a very long blockquote line that should be wrapped while preserving the source style and markdown structure.

# After
> This is a very long blockquote line that should be wrapped
> while preserving the source style and markdown structure.

Definition list reflow

A definition (the text after a : marker) reflows like a paragraph:

  • The first line keeps the marker and the spacing after it as written
  • Wrapped lines are indented to the column where the definition's text starts, and to at least four columns. Python-Markdown (MkDocs) reads a line indented less than four as part of the definition only when no other definition follows it, so a narrower indent could turn the text into a new term
  • A later paragraph of a definition keeps the indentation it has
  • Terms are never reflowed
  • A list or blockquote inside a definition reflows the way it does anywhere else
  • A definition whose text a hard break splits, with a line after the break indented less than the text, is left as written: indenting one part and not the other would end the definition at that line in Python-Markdown

Example (line-length = 40):

# Before
Term
: Aliquam metus eros, pretium sed nulla venenatis.
: Duis mollis.

# After
Term
: Aliquam metus eros, pretium sed
    nulla venenatis.
: Duis mollis.

Reflow Modes

The reflow-mode option controls how text is reformatted when reflow is true:

default mode

Standard text wrapping that breaks lines at word boundaries to fit within the configured line length.

[MD013]
line-length = 80
reflow = true
reflow-mode = "default"

normalize mode

Normalizes all paragraph text to consistently wrap at the configured line length, removing irregular line breaks.

[MD013]
line-length = 80
reflow = true
reflow-mode = "normalize"

This mode is useful for standardizing documents with inconsistent line wrapping.

sentence-per-line mode

Enforces one sentence per line, making diffs cleaner and easier to review, among other advantages. This mode:

  • Detects sentence boundaries (periods, exclamation marks, question marks)
  • Handles common abbreviations (e.g., i.e., Mr., Dr., Ph.D., Inc., etc.) without breaking sentences
  • Preserves decimal numbers and ellipses
  • Works with markdown formatting: a boundary is only recognized in prose, never inside a link's text, destination or title, an image's alt text, a code span, a wikilink, a math span or an HTML tag, so [See fig. 2. Then read on](url) stays whole. A sentence may start with a link or image; the capital behind the opener counts as its first letter, so First sentence. [Second sentence](url) here. splits before the link. A bracket is a link only where the parser reads one, so [First](unterminated and a citation like Claim. [Smith 2020] are prose and do not start a sentence, unless [smith 2020]: url is defined in the document, which makes the citation a shortcut reference link and a sentence opener
  • Ends a sentence that closes inside an emphasis, strong or strikethrough span. The closing markers are read as a run, so any length and any nesting ends the sentence they close: ~Struck.~, **Bold.**, ***Emphasized.*** and **_Bold ital._** all break before the sentence that follows. A closing quote may sit ahead of the run, as in He said "Done."** Next.
  • Treats a line holding nothing but a link or image as content rather than as a paragraph boundary. Where such a line continues the sentence above it, the sentence is joined back onto one line. The width-driven modes (default, normalize) instead leave that line where the author put it, since joining it would build a line the width check then refuses to wrap. A link line that is its own paragraph is left alone in every mode
[MD013]
line-length = 80
reflow = true
reflow-mode = "sentence-per-line"

Example transformation:

# Before
This is the first sentence. This is the second sentence. And this is the third.

# After
This is the first sentence.
This is the second sentence.
And this is the third.

This mode is particularly useful for:

  • Technical documentation where each sentence often contains a single concept
  • Documents maintained in version control where sentence-level diffs are clearer
  • Collaborative writing where different authors work on different sentences

Safety exception: a sentence is kept on the previous line when placing it on its own line would change the document's structure. Text that starts with a list marker (-, *, +, 1.), blockquote marker (>), heading marker (#), code fence, horizontal rule, reference definition ([label]:), or block-level HTML tag becomes real block syntax at the start of a line, so reflow never puts it there:

# Stays on one line (the dash clause would otherwise become a list item)
Google Calendar (Can't we get rid of this dependency? - I don't really see the need)

Structure always wins over strict one-sentence-per-line in these cases. The same guard applies to line wrapping in all reflow modes, where a wrapped line is instead broken one word earlier (or left slightly over the limit when no earlier break point exists).

When wrapping, an ordered marker counts only when it could genuinely interrupt the paragraph, which means numbered 1 with content after it. 7. item and a bare 123456. are prose to the parser, so a wrapped line may start with them. Sentence-per-line output is stricter: every line it produces ends a sentence, and a line opening 2. Do that. under one reads as a list item (MD032 reports it as one), so an inline enumerator of any number stays on the line of the sentence before it: Steps: 1. Do this. 2. Do that. becomes Steps: 1., Do this. 2., Do that. rather than a line opening with 2..

By default, punctuation inside a link or image does not end the surrounding sentence. To consider terminal link text and image alt punctuation, enable:

[MD013]
reflow = true
reflow-mode = "sentence-per-line"
link-text-punctuation = "trailing"

With this option, these paragraphs:

Read [Done.](https://example.com) Next sentence.

See ![Done.](image.png) Next sentence.

查看 ![完成。](image.png) 下一句开始。

become:

Read [Done.](https://example.com)
Next sentence.

See ![Done.](image.png)
Next sentence.

查看 ![完成。](image.png)
下一句开始。

The option also applies to sentence detection in sentence-pack and semantic-line-breaks modes. It has no effect in default or normalize mode. Only terminal literal punctuation counts: an internal period in [Done. More words](url), a destination, title, code span, HTML, autolink, or entity such as &#46; supplies no sentence ending. A backslash-escaped period (\.) counts as literal punctuation. Inline emphasis is allowed, and a linked image stays inside its outer link. Reference links and images count only when their labels are defined in the document. Punctuation-only labels such as [?](help) do not end sentences.

With "trailing", the checker uses custom abbreviations for prose as well as labels. Semantic reflow also preserves every detected sentence boundary when merging short lines, including endings inside emphasis such as **Done.**.

ASCII punctuation requires the next sentence to start with an uppercase letter, digit, or CJK character, including when require-sentence-capital is false. This keeps Visit [Yahoo!](url) today. and See [What's new?](url) for details. together. Abbreviations (including custom ones), initials, numeric labels, and structural safeguards still apply. CJK punctuation respects cjk-soft-break; a new break is never inserted where it would introduce a visible space the source did not contain.

sentence-pack mode

Keeps complete sentences together while allowing several short sentences on one line. The line-length is a soft budget: the next complete sentence joins the current line only when the combined width fits. A sentence wider than the budget gets its own line and is never split at words or clauses.

[MD013]
line-length = 80
reflow = true
reflow-mode = "sentence-pack"

Before:

First short sentence.
Second short sentence. This deliberately long sentence remains one indivisible editing unit even when its display width exceeds the configured soft limit.

After:

First short sentence. Second short sentence.
This deliberately long sentence remains one indivisible editing unit even when its display width exceeds the configured soft limit.

Sentence detection follows sentence-per-line, including custom abbreviations and require-sentence-capital. Width follows length-mode and includes list and blockquote prefixes. The existing reflow-length-exemptions option also applies. With cjk-soft-break = "join", eligible CJK soft breaks remain unspaced when sentences are packed, while spaces the author wrote remain spaces. Adjacent CJK sentences connected by authored whitespace stay in the same pack unit because a soft line break cannot preserve that separator.

Hard breaks, paragraph boundaries and protected Markdown constructs are preserved. The structure-safety exception described above also applies: sentences stay together if a break would create a list, heading or other block. Footnotes containing hard breaks are left as written. With line-length = 0, adjacent sentences join without a width limit, but hard breaks and paragraph boundaries still remain.

check reports paragraphs whose sentence packing would change, even if no line exceeds the budget. A correctly placed oversized sentence is not a paragraph line-length violation. Formatting again leaves the result unchanged. This mode is opt-in; other reflow modes and defaults are unchanged.

semantic-line-breaks mode

Breaks lines at semantic boundaries using a cascading strategy. Unlike sentence-per-line (which always breaks at every sentence boundary only), this mode also splits long sentences at clause punctuation and break-words to keep lines within the configured line length.

Balanced ASCII parenthetical asides (( ... )) stay together during sentence detection, including questions such as (does it? I'm not sure). Pairing follows nesting within each reflow segment; explicit Markdown hard breaks end segments. An aside that exceeds the configured width uses its inner sentence boundaries before further width wrapping. Existing sentence boundaries at or after its closing edge remain available. Delimiters inside Markdown links, inline code, HTML tags, and math constructs do not delimit prose asides; bare URL text follows the prose pairing rules. Escaped and unmatched delimiters stay ordinary text. Distant emoticons such as :( ... :) form a lexical pair too.

Diagnostic sentence counts treat an aside balanced within the supplied prose as one unit before width wrapping. A paragraph diagnostic counts joined prose before hard-break segmentation; some container diagnostics count only rewritten prose segments. These counts can differ from the number of formatted output lines.

Cascading priority:

Priority Split point When applied
1 Sentence boundaries (. ! ?) Always
2 Clause punctuation (, ; : —) When line > line-length
3 Break-words (and, or, but, which, because, ...) When line still > line-length
4 Word wrap Fallback
[MD013]
line-length = 80
reflow = true
reflow-mode = "semantic-line-breaks"

Example transformation:

# Before
All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.

# After (with line-length = 80)
All human beings are born free and equal in dignity and rights.
They are endowed with reason and conscience
and should act towards one another in a spirit of brotherhood.

Break-words list: and, or, but, nor, yet, so, for, which, that, because, when, if, while, where, although, though, unless, since, after, before, until, as, once, whether, however, therefore, moreover, furthermore, nevertheless, whereas

Add project-specific or localized break words through configuration:

[MD013]
reflow = true
reflow-mode = "semantic-line-breaks"
break-words = ["parce", "puisque", "porque"]

These words join the built-in list and follow the same split priority and width rules. Code spans, links, and parenthetical groups retain their existing protection from break-word splits.

With line-length = 0, only semantic sentence boundaries are used (no width cascading); balanced asides remain together.

Sentence-per-line without line length warnings

If you want to use sentence-per-line mode for formatting but don't want warnings about long sentences, you can disable paragraph checking while keeping code blocks and tables checked:

[MD013]
line-length = 80
paragraphs = false  # Don't warn about long paragraphs
code-blocks = true  # Still check code blocks
tables = true  # Still check tables
reflow = true
reflow-mode = "sentence-per-line"

This configuration is useful when:

  • You want automatic sentence-per-line formatting without validation noise
  • You care about line length in code blocks and tables but not in regular text
  • You're using semantic line breaks where sentence length is determined by content, not arbitrary limits

Disabling all line length checks

If you want to completely disable all line length checking (for paragraphs, headings, code blocks, and tables), set line-length to 0:

[MD013]
line-length = 0  # Disable all line length checks
reflow = true
reflow-mode = "sentence-per-line"

When line-length is set to 0, no line length warnings will be reported for any content type. This is particularly useful for:

  • Projects using semantic line breaks where lines break at logical boundaries regardless of length
  • Sentence-per-line workflows where line length is not a concern
  • Documentation where long lines (e.g., URLs, technical terms) are unavoidable and acceptable

Note: With line-length: 0 and reflow-mode: "sentence-per-line", rumdl will:

  • Split multiple sentences that share a line into separate lines
  • Join single sentences that span multiple lines into one line (since there's no length constraint)
  • Provide consistent "one sentence = one line" formatting throughout your document

Example with automatic reflow

[MD013]
line-length = 80
reflow = true

With this configuration, long lines will be automatically wrapped to fit within 80 characters while maintaining proper Markdown formatting.

Note: When reflow is false (default), automatic fixes are not available and you'll need to manually wrap long lines.

Markdown with Gherkin

Under the mdg flavor with reflow enabled, MD013 reports an over-long unordered list item but offers no fix for it. Gherkin steps are unordered Markdown list items, and Gherkin keywords are localized, so the word after the marker cannot be recognized without the complete dialect table; rather than guess, the flavor withholds reflow from every unordered item, because wrapping one would change the step's Gherkin text. Ordered list items are reflowed as usual.

See Markdown with Gherkin Flavor for the full flavor specification.

Learn more

  • MD009: Remove trailing spaces at line ends
  • MD010: Use spaces instead of tabs
  • MD047: End files with a single newline