Right, let’s talk about Hugo’s built-in shortcodes. Think of these as your get-out-of-jail-free cards for embedding content that would normally require a tedious mix of raw HTML, external scripts, and a prayer to the internet gods. They’re Hugo’s way of saying, “I got you, friend. Don’t sweat the tedious stuff.”
The Workhorse: figure
You’ll use figure more than any other. It’s for images, but it does the job properly. Unlike just slapping an <img> tag in your Markdown, figure automatically handles the alt text, caption, and wrapping it all in the semantically correct HTML5 <figure> element. It also gives you optional classes for styling and even lightbox functionality.
Reality vs. expectation, a photo essay.
Why you care: Accessibility, SEO, and clean code. The alt text is properly placed, and the caption is logically tied to the image. The common pitfall? Forgetting that the image path is relative to your static directory. If your image is at static/images/logo.png, you reference it as /images/logo.png. Hugo doesn’t guess; it looks where you told it to look.
The Code Masters: highlight and gist
The highlight shortcode is what takes your fenced code blocks (```) and makes them pretty. You can also call it directly for more control. The required language parameter tells Chroma (Hugo’s syntax highlighter) which lexer to use.
{{<highlightpython"linenos=table,hl_lines=2 4-5">}}def this_is_a_function(that_does_nothing):
# This line is highlighted
return "This is a string" # So are these two
print("This is a print statement")
{{</highlight>}}
The gist shortcode is brilliantly simple. Found a useful code snippet on GitHub Gist? Just grab the ID from the URL (https://gist.github.com/username/a1b2c3d4e5f6) and drop it in. Hugo will fetch and render the whole thing for you.
{{<gistspf137896402>}}
Why you care: It keeps your code examples versioned with your content. If the Gist changes, your site’s code example stays exactly as it was when you wrote the post. It’s a snapshot.
The Embedders: tweet and youtube
These are black magic. You give them an ID, and they return the fully formed, often interactive, embed. No need to paste in gnarly HTML from a third-party site.
The rough edge: The Twitter embed can be… temperamental. Sometimes it just doesn’t load in a development environment. Don’t panic. It usually sorts itself out in the production build. It’s not you, it’s Twitter’s often-byzantine embed script.
The Navigation Aids: ref and relref
These aren’t for content; they’re for smart linking. This is Hugo superpowers 101. You give them the path to a content file (like blog/my-post.md), and they output the absolute (ref) or relative (relref) permalink for it.
Check out my [definitive guide to toast]({{<ref"posts/toast-theory.md">}}).
<!-- Outputs: /posts/toast-theory/ -->Or, for a relative link inside a `<head>` tag:
<linkrel="canonical"href="{{<relref"posts/toast-theory.md">}}">
<!-- Outputs: /posts/toast-theory/ -->
Why you care: You never hardcode a URL again. Move content around, change your site structure, it doesn’t matter. These shortcodes will always resolve to the correct link. The pitfall is that the path must be relative to the content directory and include the file extension. Get it wrong, and Hugo will scream at you, which is better than a silent broken link.
The Misfit: param
This one’s a bit of an oddball. It doesn’t embed content; it fetches a value from your site’s configuration. Need to display your site’s title in a layout without hardcoding it? param is your friend.
My site is called: {{<param"title">}}.
<!-- If config.toml has title = "My Brilliant Site", it outputs that -->
It’s niche, but when you need it, it’s incredibly useful for making your templates truly dynamic and config-driven.
The designers made a solid choice here. These cover 99% of the annoying external content you’d ever want to include, and they do it in a way that keeps your content files clean, semantic, and portable. Use them liberally.