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 to0to 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. Whenfalse, a line is not reported if it would fit within the limit once its inline code spans are excluded - useful withreflowso an unbreakable code incantation does not fail an otherwise-clean filetables: 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. Whenfalse, 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 (ascode-blocks = falsealso 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 reasoncode-spansis a separate option fromcode-blocks. Like the other block flags, this has no effect understrict. 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 commentbracket-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 = falsealso 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-lengthis still used for reflow but no warnings are reported. Blockquote content is treated as paragraph text, soparagraphs = falsealso skips blockquotesblockquotes: Whether to check line length in blockquote content (default:true). Set tofalseto skip blockquote lines specifically without disabling all paragraph checksstrict: When true, disables exceptions for URLs and other special content (default:false). Overridesstern.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'ssternoption.ignore-link-urls: Whether to forgive a line that exceeds the limit only because of the URL inside an inline[text](url)/(default:true; see Ignoring inline link URLs). Set tofalseto count those URLs toward the line length. Combined withstern, 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 thansternabout links, but withoutstrictflagging genuinely unbreakable link lines. Has no effect understrict(which already disables all forgiveness). The former keysemantic-link-understandingis still accepted as an alias.heading-line-length: Per-context maximum length for heading lines. Unset (null) falls back toline-length;0means "no limit for headings". Mirrors markdownlint'sheading_line_lengthoption.code-block-line-length: Per-context maximum length for fenced or indented code-block lines. Unset (null) falls back toline-length;0means "no limit for code blocks". Mirrors markdownlint'scode_block_line_lengthoption.reflow: When true, enables automatic text reflow to wrap long lines intelligently (default:false)reflow-mode: Controls how text is reflowed whenreflowis 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 acceptslink_text_punctuation.break-words: Additional words that can begin a new line insemantic-line-breaksmode (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, onlyword. Capitalis 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.andReleased in 2020. 3rd edition.split,See fig. 3andThe count was 5. and that was alldo not - When
false,word. lowercaseis also treated as a sentence boundary (more splitting) - In
sentence-per-linemode, 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?" guidestays 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, soChoose File... `Open Folder` appears in the menu.stays one, and not after a bare digit, so the enumerationSteps: 1. `init` the repo, 2. `build` it.and the versionPinned 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). Whentrue, these spans are treated as atomic units. Whenfalse, they can be wrapped word-by-word like normal text. An emphasis/strong/strikethrough span that is on its own longer thanline-lengthis wrapped even whenatomic-spansistrue, 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 whileatomic-spansistrue. Whenatomic-spansisfalse, 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, setatomic-spans = falseandreflow-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 rulesatomic-spansapplies to emphasis spans: only when the whole construct is longer thanline-length(or freely, whenatomic-spansisfalse). 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 whenatomic-spansisfalse(default:true). Set it tofalseto keep code spans whole while emphasis, strong and strikethrough still wrap. It has no effect whileatomic-spansistrue, which already holds code spans whole. The whitespace, container and indentation safeguards always apply. A code span longer thanline-lengthstays whole on its own line, and the check reports that line under its usual rules (code-spans,strict,stern); thecode-spansoption is the length-check exemption for such lines, not a wrapping controlreflow-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 consultsignore-link-urls(an inline[text](url)costs[text],costs![alt]) andcode-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.
Ignoring inline link URLs (non-strict mode)¶
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
 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:
 - Nested badge patterns:
[](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-urlsdecides 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.sternandcode-spansleave reflow alone in the same way.strictis 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-packandsemantic-line-breaksshape 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. Setreflow-length-exemptions = trueto have reflow honor this exemption, orreflow = falseto keep those lines as authored. ignore-link-urls = false: count inline link/image URLs toward the line length. Withstern, 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:
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 (
中文andEnglish). - 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. Usemath-blocks = falseto 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.
normalize mode¶
Normalizes all paragraph text to consistently wrap at the configured line length, removing irregular line breaks.
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, soFirst sentence. [Second sentence](url) here.splits before the link. A bracket is a link only where the parser reads one, so[First](unterminatedand a citation likeClaim. [Smith 2020]are prose and do not start a sentence, unless[smith 2020]: urlis 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 inHe 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
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..
Sentence endings in links and images¶
By default, punctuation inside a link or image does not end the surrounding sentence. To consider terminal link text and image alt punctuation, enable:
With this option, these paragraphs:
Read [Done.](https://example.com) Next sentence.
See  Next sentence.
查看  下一句开始。
become:
Read [Done.](https://example.com)
Next sentence.
See 
Next sentence.
查看 
下一句开始。
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 . 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.
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 |
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¶
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.