Markdown is easy to write and quietly inconsistent to render. The same file can look correct in a pull request, lose its tables in a docs site, and fail the build in an MDX pipeline, because those three tools implement three different dialects. Most of the problems come from a small set of rules about blank lines, indentation and where a block starts. The mistakes below are the ones that actually cost time, with the specific rule behind each and the version that works everywhere.
Markdown is block-based, and a block usually needs an empty line before it. Write a sentence and put a list on the next line with no gap, and CommonMark treats the whole thing as one paragraph with literal hyphens in it. The same applies to a fenced code block, a table, and a blockquote after a paragraph. GitHub's renderer is forgiving about lists in some positions, which is why a file looks right in a pull request and falls apart in a static site generator using a stricter parser. Leave the blank line every time and the ambiguity disappears.
A single newline inside a paragraph is not a line break — it renders as a space. To force a break you either end the line with two trailing spaces, which is invisible, survives no editor that trims whitespace, and is stripped by most formatters, or you end it with a backslash, which CommonMark supports and reads clearly, or you write <br>. For addresses and verse, the backslash is the one that survives round-tripping through tooling.
Separately, decide how you wrap source lines and be consistent. Hard-wrapping at 80 columns looks tidy but means changing one word reflows the paragraph and the diff shows five changed lines. One line per paragraph gives a diff that highlights exactly the sentence you edited, at the cost of horizontal scrolling. One sentence per line is the compromise that reviews best in Git.
A fenced block indented to line up under a list item needs enough indentation to belong to that item. If the list marker plus space is two characters, the fence needs two spaces; inside a nested list it needs more, and the legacy four-space indented-code syntax inside a list item needs eight. Get it wrong and the code either escapes the list or renders as plain paragraph text with the backticks visible.
Always label the fence. ```bash rather than bare backticks costs four characters and gives you syntax highlighting plus, in some tooling, a copy button and correct screen-reader language. If the block itself contains triple backticks, use four backticks on the outer fence — nesting by indentation will not work.
YAML front matter must start on line one, column one, with ---. A single blank line above it and the parser sees a horizontal rule followed by text, and your post publishes with a title of "title: My Post". Unquoted values with a colon in them break the same way, so quote anything containing :, # or a leading @.
For headings, use ATX (## Section) rather than the setext underline style, which only reaches two levels and can be created accidentally by a line of dashes under a sentence. Do not skip from h2 to h4; assistive technology uses the outline to navigate. And if your site template already renders the front-matter title as the h1, a second h1 in the body gives the page two.
Tables, footnotes, task lists, strikethrough and bare-URL autolinking are all GitHub Flavored Markdown extensions, not CommonMark. Move a README into a docs site running a plain CommonMark parser and the tables become pipe soup. A GFM table also requires the alignment row of dashes under the header — a two-row table with no separator is just a paragraph. MDX adds a further trap: it parses the file as JSX, so a stray < or an unescaped brace throws a build error rather than rendering as text.
Raw HTML is allowed by the spec but not by every consumer. npm strips most of it from README rendering, and many comment systems and email clients sanitise it away. If a table needs HTML to express a merged cell, expect that cell to disappear somewhere.
Relative image paths like  break the moment the file moves directory or is rendered at a different URL depth — a docs page at /guide/ versus /guide/intro/ resolves them differently. Use root-relative paths for anything published. Separately, turn off smart quotes and em-dash substitution in whatever editor you use: an autocorrected curly apostrophe inside a code sample produces a syntax error that is genuinely hard to see.
Run markdownlint-cli2 or remark-lint in CI to catch skipped heading levels, missing blank lines and unlabelled fences, and run Prettier over the files to normalise list markers and emphasis characters so nobody argues about asterisks versus underscores. A quick reference for the syntax itself is in the Markdown cheat sheet.