Hard-Wrap or Soft-Wrap Your Notes? The Diff Decides
Wrap width is diff granularity. If your note is one long line, a one-word edit rewrites that whole line in git diff. If your note is hard-wrapped at 80 columns, a one-word edit rewrites one line. Neither is universally right. The diff you want to read tomorrow decides the wrap you author today 1 2.
Prettier ships this argument in three lines of documentation. Its proseWrap option defaults to "preserve", not "always" or "never", because "some services use a linebreak-sensitive renderer, e.g. GitHub comments and BitBucket" 3. The tool refuses to overwrite an intent it can't infer. This post walks you through the diff-test — the four-step decision procedure that infers the intent for you, then names the tool you set to respect it.
What CommonMark actually says about a line break
CommonMark treats a soft line break as whitespace, and a hard line break as an explicit switch — either two trailing spaces or a backslash at the end of the line — that renders as a <br /> tag 1. That single fact is the quiet reason your line break didn't show up. A lone Enter is a soft break; the renderer collapses it into a space. Two spaces or a backslash is the toggle you were missing 4.
The spec is short about this on purpose. Example 634 gives the backslash the same status as the two-space form, verbatim: "For a more visible alternative, a backslash before the line ending may be used instead of two or more spaces" 1. GitHub restates the identical rule in its writing docs for .md files 4. Issues, Discussions, and PR comments, however, do something different — and that difference is where the wrap debate begins.
The two camps, stated fairly
There are three defensible positions on how to wrap a Markdown note, and they disagree about what a good diff looks like. Position A leaves each paragraph as one long line and lets the editor wrap visually. Position B hard-wraps every paragraph at a fixed column (usually 72–80). Position C — semantic line breaks — breaks after each substantial unit of thought instead of at a column count 5.
Position A gives short files and paragraph-scoped diffs. Line-length arithmetic never leaks into content decisions.
Position B gives rectangular files that fit any editor at any width. Linux kernel style calls it: "The preferred limit on the length of a single line is 80 columns. Statements longer than 80 columns should be broken into sensible chunks, unless exceeding 80 columns significantly increases readability and does not hide information" 6. Even the strictest authority lets you off.
Position C is old. Brandon Rhodes named the modern practice in 2012: "Instead of fussing with the lines of each paragraph so that they all end near the right margin, they can add linefeeds anywhere that there is a break between ideas… your version-control system will love semantic linefeeds" 7. Mattt's Semantic Line Breaks specification made it precise around 2017: "When writing text with a compatible markup language, add a line break after each substantial unit of thought," and "A semantic line break MUST NOT alter the final rendered output of the document" 5. Robert Lin (bobheadxi) extended the argument into modern developer-review terms in 2021 8.
The deeper thread is 1974. Brian W. Kernighan's Bell Labs Technical Memorandum 74-1273-18, "UNIX for Beginners," told writers preparing documents in nroff: "Start each sentence on a new line. Make lines short, and break lines at natural places, such as after commas and semicolons, rather than randomly" 9. Everything since is a rediscovery.
Semantic line breaks are honest about their cost
Semantic line breaks are beautiful in a .md file and brittle in two real places. Position C wins on clause-level diffs and loses on renderers that treat a single newline as content, so the case for it fails if you skip the caveats. The Hacker News thread on the sembr spec surfaced both objections in one weekend of comments 10.
The em-dash collision. The sembr spec says "A semantic line break SHOULD occur after an […] em dash (—)" 5. On Hacker News in September 2025, one commenter (chrismorgan) put the objection plainly: "I agree with this, however it means that no existing markup language supports semantic line breaks, because every last one of them just turns the break into a space — and em dashes are, in most locales, not to be surrounded by a space. Consequently, you'll end up with a stray space if you do this" 10. That is a real, load-bearing objection: a soft break between the words on either side of an em dash renders as a space, and typographic convention says no space.
The GitHub-Issues collision. GitHub's .md renderer follows CommonMark; a single Enter is whitespace and semantic breaks read cleanly. GitHub Issues, Discussions, and pull-request comments do not — a single \n in that context is rendered as <br>. On the same HN thread, account42 made the pro-hard-single-linebreak case: "The problem is that this makes having line breaks that are not paragraph breaks in the output much more awkward, and I think those are much more important than line breaks that are only there in the source" 10. Semantic breaks work in the file; they insert extra <br> in the comment box.
Both objections are correct. Both are why sembr.org's own FAQ tells you: "git diff can normalize line changes in a way that may obscure certain revisions to text with semantic line breaks. You can pass the --word-diff option to the git diff command for better results" 5. If you pick semantic line breaks, you accept the cost, and you learn git diff --word-diff.
Why the numbers cluster at 65–80
Every widely used prose reformatter picks a width in the 70-something range. That is not a punch-card accident but a converged answer to a typographic question about how many characters the eye can track without losing its place. Robert Bringhurst's Elements of Typographic Style — via Richard Rutter's web mirror — collects the consensus: "Anything from 45 to 75 characters is widely regarded as a satisfactory length of line" with "the 66-character line… widely regarded as ideal" 11.
Every tool sits inside that band. GNU fmt defaults to -w 75 maximum with a goal of 93% of width — roughly 70 12. GNU Emacs's M-q (fill-paragraph) fills to fill-column, "the default value (see Local Variables) is 70" 13. Vim's gq uses 'textwidth'; when it's 0, the length is the screen width capped at 79 14. Pandoc's --wrap=auto wraps to --columns (default 72) 15. Kernel style says 80. Bringhurst says 66. If four independent codebases converge on 65–80, the number measures how long a human sentence can be before the eye loses its place 11.
The diff-test — one procedure that decides for you
Do this for the specific note you are wrestling with. It takes four minutes and gives you a per-note answer that a general opinion never will. The test replaces argument with a diff you can read.
- Write two versions of the same paragraph. Save the paragraph as one long line in
note-soft.md. Save the same paragraph, hard-wrapped at 80 columns, innote-hard.md. Same content. Different shape. - Change one word in the middle. Not the first word, not the last. Somewhere in the third sentence of the third line.
- Run
git diff --no-index note-soft.md note-soft.edited.mdand the same on the hard-wrapped pair. Look at the two red/green blocks side by side. - Ask: which diff can you read? If the soft-wrap diff is a wall of red and green rewrapping the whole paragraph and the hard-wrap diff is a one-line swap, the note wants hard-wrap. If the soft-wrap diff is a clean single-line swap because the paragraph is short, the note wants soft-wrap. If the note is prose you edit at the clause level — code-review comments, spec text, legal — try the same test with semantic line breaks and
git diff --word-diff, then read that.
The test is the decision procedure. There is no verdict beyond the diff you can read tomorrow.
Common mistakes
Five failure modes show up most often when a repo picks a wrap policy without a diff-test to anchor it. Each is easier to spot than to unwind after two months of commits, so read this list before the wrap discussion happens, not after.
- Reflowing a hard-wrapped file with a tool that resets the width. Running
fmt -w 100over a repo hard-wrapped at 72 rewrites every line in every paragraph. The diff is unreadable. Pick one width per repo and keep it there 12. - Using single-space line breaks and expecting a
<br>. In.mdfiles on GitHub, the break requires two spaces at the end of the first line, or a backslash at the end of the first line 4. One space is invisible whitespace; the render collapses it. - Semantic line breaks in a linebreak-sensitive box. Pasting sembr-shaped prose into a GitHub Issue or Discussion inserts a
<br>at every clause 10. The prose looks like a poem no one asked for. Save sembr for.mdfiles. - Assuming Prettier will hard-wrap for you. The default is
preserve— Prettier will not change your wrapping 3. Set"proseWrap": "always"and aprintWidthexplicitly if you want it to. - Forgetting
--word-diff. If you soft-wrap prose or use semantic line breaks, the defaultgit diffshows whole-paragraph or whole-clause changes.git diff --word-diffshows the actual word changes and makes reviews readable 5.
Tools that respect your choice
MNMNOTE saves the file exactly as you type it — the wrap you author is the wrap on disk, and the wrap on disk is the wrap git diff reads. It has no built-in prose reformatter, so the choice of tool at the boundary is yours. The row-per-tool table below is the one-page reference for how each option handles a Markdown paragraph.
| Tool | Wrap default | How to override | Diff behavior |
|---|---|---|---|
GNU fmt | -w 75 max; -g = 93% of width (~70) | fmt -w 80 -g 72 file.md | rewrites paragraphs; the diff spans reflowed lines 12 |
Vim gq | uses 'textwidth'; if 0, screen width capped at 79 | :set textwidth=80 then gqip | reflows the paragraph; diff-friendly if width is stable 14 |
Emacs M-q | fill-column default 70 | C-x f to set, or (setq-default fill-column 80) | reflows current paragraph; combine with git diff --word-diff 13 |
| Prettier | proseWrap: "preserve" | set "proseWrap": "always" + printWidth in .prettierrc | wraps to printWidth on save; preserves your shape if preserve 3 |
| Pandoc | --wrap=auto, --columns=72 | pandoc --wrap=none (single-line) or --wrap=preserve | fully controllable at conversion time 15 |
| GitHub renderer | linebreak-sensitive in Issues/Discussions/comments; CommonMark in .md | not user-configurable | comments break when auto-reflowed 4 |
git diff --word-diff | default is line-diff | git diff --word-diff or --word-diff=color | shows within-line word changes; the answer to soft-wrap ergonomics 5 |
Steph Ango calls the deeper argument "file over app": "Apps are ephemeral, but your files have a chance to last" 16. Wrap is a property of the file. Whichever camp you land in, the tool you use tomorrow should read your file the same way today's tool does — every tool above respects the shape you author. If yours doesn't, replace the tool, not the shape 17.
Frequently Asked Questions
The seven questions below are the ones a reader arrives with. Answers stay short so a language model can lift them, and each maps to a section above so you can follow the argument back to the primary source.
Should I hard-wrap my Markdown at 80 columns?
It depends on what you diff. If you review the file with git diff, hard-wrap at a fixed width (72–80) so a one-word change produces a one-line diff. If you never diff and always edit through a WYSIWYG, soft-wrap and forget the ruler. Prettier defaults to "preserve" for exactly this reason 3. Test both against your own diff to decide.
How wide should I wrap plain-text notes?
Somewhere in the 65–80 range, and the same width across the repo. Bringhurst's typographic measure sits at 45–75 characters with 66 "widely regarded as ideal" 11. fmt defaults to 75 with a 70 goal 12; Emacs fill-column defaults to 70 13; Vim's gq caps at 79 when textwidth is 0 14; Pandoc's default is 72 15. Pick one — 72 or 80 are both fine — and stop tuning.
Why doesn't my Markdown line break show up?
Because CommonMark treats a single newline as whitespace. To force a <br> you need two or more spaces at the end of the line, or a backslash 1. GitHub restates the same rule in its writing docs for .md files 4. If you want the break to render, add the two spaces (or use a blank line for a paragraph break).
What is the difference between a hard and soft line break in Markdown?
A soft break is a plain newline in the source; the renderer turns it into a space between words. A hard break — two trailing spaces or a backslash — becomes a <br /> tag in HTML 1. Hard breaks are for line-scoped structure (addresses, verse); paragraph breaks are for prose.
Are semantic line breaks better than hard-wrapping at 80?
They are better for prose you review at the clause level, worse for prose you paste into a linebreak-sensitive box. The spec says "A semantic line break MUST NOT alter the final rendered output" 5, but the em-dash-and-space collision and the GitHub-Issues \n = <br> collision are real 10. Run the diff-test on your own file and pick.
How do I make git diff show word changes in Markdown?
git diff --word-diff — or git diff --word-diff=color for terminal highlighting. sembr.org's own FAQ recommends it because "git diff can normalize line changes in a way that may obscure certain revisions to text with semantic line breaks" 5. It also makes soft-wrapped paragraphs diff-readable.
Does Prettier hard-wrap my Markdown?
Only if you tell it to. The default proseWrap: "preserve" leaves your wrapping alone 3. To hard-wrap, set "proseWrap": "always" and a printWidth in .prettierrc. To un-wrap, set "proseWrap": "never".
MNMNOTE saves the file exactly as you type it — the wrap on your screen is the wrap on disk, and the wrap on disk is the wrap the diff reads. Run the four-minute diff-test on your next note, pick a shape, and configure one tool to keep it. mnmnote.com lives in your browser; the file is yours.
Footnotes
-
MacFarlane, J. et al. "CommonMark Spec v0.31.2 §6.7 Hard line breaks." 2024-01-28. https://spec.commonmark.org/0.31.2/#hard-line-breaks. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 ↩5
-
MNMNOTE. "Every design decision, made twice." https://blog.mnmnote.com/posts/every-design-decision. Accessed 2026-07-02. ↩
-
Prettier. "Prose Wrap — Options." First available in v1.8.2. https://prettier.io/docs/options#prose-wrap. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 ↩5
-
GitHub Docs. "Basic writing and formatting syntax." https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 ↩5
-
Mattt. "Semantic Line Breaks — Specification (and FAQ)." ~2017 (living spec, CC-BY-4.0). https://sembr.org/. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Linux Kernel documentation. "Linux kernel coding style §2 — Breaking long lines and strings." https://docs.kernel.org/process/coding-style.html. Accessed 2026-07-02. ↩
-
Rhodes, B. "Semantic Linefeeds." 2012-04-03. https://rhodesmill.org/brandon/2012/one-sentence-per-line/. Accessed 2026-07-02. ↩
-
Lin, R. (bobheadxi). "Semantic line breaks." 2021-02-18. https://bobheadxi.dev/semantic-line-breaks/. Accessed 2026-07-02. ↩
-
Kernighan, B. W. "UNIX for Beginners." Bell Labs Technical Memorandum 74-1273-18, 1974-10-29, §"Hints for Preparing Documents." Captured via Rhodes 2012 with linked Internet Archive scan (see 7). Accessed 2026-07-02. ↩
-
Hacker News item 45157505, "Semantic Line Breaks (2017)," discussion thread, 2025-09-07. Comments by
chrismorgan(em-dash collision) andaccount42(GitHub-Issues\n=<br>collision). https://news.ycombinator.com/item?id=45157505. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 ↩5 -
Bringhurst, R. The Elements of Typographic Style §2.1.2, quoted in Rutter, R. The Elements of Typographic Style Applied to the Web. https://webtypography.net/2.1.2. Accessed 2026-07-02. ↩ ↩2 ↩3
-
GNU coreutils. "
fmt(1)— simple optimal text formatter." https://man7.org/linux/man-pages/man1/fmt.1.html. Accessed 2026-07-02. ↩ ↩2 ↩3 ↩4 -
Free Software Foundation. "GNU Emacs Manual §26.6.2 — Explicit Fill Commands." https://www.gnu.org/software/emacs/manual/html_node/emacs/Fill-Commands.html. Accessed 2026-07-02. ↩ ↩2 ↩3
-
vimhelp.org. "Vim documentation:
change.txt—gq." https://vimhelp.org/change.txt.html#gq. Accessed 2026-07-02. ↩ ↩2 ↩3 -
MacFarlane, J. "Pandoc User's Guide —
--wrapand--columns." https://pandoc.org/MANUAL.html#option--wrap. Accessed 2026-07-02. ↩ ↩2 ↩3 -
Ango, S. "File over app." 2023-07-01. https://stephango.com/file-over-app. Accessed 2026-07-02. ↩
-
MNMNOTE. "Local-first: own your data (2026)." https://blog.mnmnote.com/posts/local-first-own-your-data-2026. Accessed 2026-07-02. ↩