7.2 CommonMark Compliance and Extensions
Right, so you’ve decided to use Markdown. Good choice. It’s the closest thing we have to a universal authoring format for the web. But Markdown isn’t a single, monolithic standard; it’s a family of dialects. Hugo, in its infinite wisdom (and for very good reasons), uses an implementation called Goldmark. Think of it as CommonMark—the sane, standardized specification—with a bunch of very useful, and occasionally bizarre, party tricks bolted on.
The CommonMark Baseline: Your New Best Friend
First, let’s talk about CommonMark. Before it came along, writing Markdown was a bit like a game of Calvinball. Every parser (looking at you, original blackfriday) had its own quirks and interpretations. A document that rendered perfectly in one system would look like a dog’s breakfast in another. CommonMark is a rigorous specification that says, “No, this is exactly how four spaces for a code block should work, and this is how nested lists should be handled.”
Hugo’s adoption of Goldmark means you get this predictability. You can write your content with the confidence that it will render consistently, not just in Hugo, but in any other CommonMark-compliant system. This is a huge win for portability and sanity. For example, this CommonMark will always work exactly as you expect:
A paragraph with `inline code` and a link to [Hugo](https://gohugo.io).
* A list item
* Another item with **strong emphasis**
Goldmark’s Extended Toolbox: The Fun Stuff
Now, the good part: Hugo doesn’t just stop at the CommonMark spec. It tells Goldmark to enable a whole suite of extensions. This is where you go from writing standard documents to crafting powerful, dynamic content without ever leaving your comfortable Markdown editor.
Typographic Tweaks: Making Things Pretty
This extension is pure quality-of-life. It automatically replaces dumb quotes with “smart quotes,” double hyphens (--) with an em dash (—), and so on. You write plain, easy-to-type characters, and Hugo outputs properly typeset text. It’s one of those things you’ll never think about until you see a site without it, and then you’ll wonder why everything looks so…dumb.
Table of Contents: Automatic Navigation
This is a killer feature. You can simply place {{ .TableOfContents }} in your template and Hugo will generate a perfectly nested table of contents from the headers in your Markdown content. The magic is that it happens at build time, so there’s zero JavaScript or client-side performance cost. It’s just pure, static, accessible HTML.
Link Rendering: A Touch of Class
This is a small but brilliant extension. You can add HTML attributes to your links right in Markdown using a simple, intuitive syntax. Want to add a class or rel attribute? Easy.
Here's a [link to my portfolio](https://my.site.com){class="text-blue-500" rel="noopener"}.
This renders as:
Here's a <a href="https://my.site.com" class="text-blue-500" rel="noopener">link to my portfolio</a>.
It keeps your Markdown clean while giving you the power of raw HTML when you need it. It’s the best of both worlds.
The Pitfalls: Where They Got Weird
Not every extension is a home run. The most common “wait, what?” moment comes with the Code Block Extension.
By default, Goldmark is hilariously, almost pathologically, strict. If you have a fenced code block and you don’t specify a language, it will wrap your code in a <pre> tag but not a <code> tag. Let me say that again: it produces invalid HTML. It’s a truly baffling default.
This is some code without a language tag.
This will output:
<pre>This is some code without a language tag.</pre>
See? No <code> in sight. The fix is simple but mandatory: in your hugo.toml/yaml/json, you must configure Goldmark to be less pedantic.
[markup.goldmark.extensions]
codeFences = false
Wait, false? Yes. Setting codeFences = false doesn’t disable code fences—that would be insane. Instead, it tells Goldmark to use its older, more sensible behavior: always wrap fenced code in <code> blocks, whether a language is specified or not. It’s a classic case of a configuration option name that describes the exact opposite of what you’d expect. I don’t know why they did it this way. I’m not sure anyone does. Just set it to false and never think about it again.
Another quirk is with raw HTML. CommonMark allows raw HTML in your Markdown, but Goldmark has it disabled by default for security. If you need it (and you often will for embedding videos or complex components), you have to explicitly enable it. It’s a sensible security default, but it can trip you up.
[markup.goldmark.renderer]
unsafe = true
The name unsafe is wonderfully dramatic, but it’s accurate. Only enable this if you trust the authors of the content going into your site.
The moral of the story is this: Goldmark gives you a rock-solid, standards-compliant foundation and then hands you a set of powerful, if occasionally quirky, tools to build on top of it. Your job is to learn which tools to use and which configuration knobs need a firm, deliberate twist to make everything work smoothly.