How to Customize and Optimize Your Hugo RSS Feed
Technical Archive
This article discusses the previous version of this blog, which was built with Hugo. The site is now powered by Astro. While the security concepts explored here remain valid, specific implementation details related to Hugo no longer apply to the live site.
RSS (Really Simple Syndication) is a standard web feed format based on XML. It allows users to subscribe to online resources—like websites or blogs—and receive immediate updates whenever new content is published.
In this guide, I will detail how to offer an RSS feed to visitors of your Hugo website and, more importantly, how to customize it to fit your specific needs.
How to enable RSS in Hugo?
Great news: it is enabled by default, so you don’t have to do anything! 😇
Running the hugo command builds your website and generates a multitude of files in your public folder. Among them, you will find a file named index.xml. This is the XML representation of your website: your RSS feed. Feed readers use this file to notify subscribers about your updates, such as newly published posts.
How to exclude content from the RSS feed?
First, take a look at your website’s index.xml. You should see a list of <item> blocks following this structure:
...
<item>
<title>Title of a page</title>
<link>https://example.com/page-link</link>
<pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
<author>Author Name</author>
<guid>https://example.com/page-link</guid>
<description>A short description...</description>
</item>
...
If an item refers to a page you want to exclude from your RSS feed (like a legal notice or a landing page), simply add the following to its frontmatter:
+++
...
hidden = true
...
+++
Re-launch your build or server. You will see that the targeted page is no longer present in the generated XML.
Control which RSS files are created
According to the Hugo RSS documentation, several feed files are created by default:
-
For the Home page (at the root of the
publicfolder); -
For Sections (e.g., inside
public/post/orpublic/page/); -
For Taxonomies (at the root of tags and categories);
-
For Terms (for every specific tag and category).
As I mentioned in my post Mastering Hugo Sitemaps: How to Exclude Pages and Improve SEO, the default file generation can be overwhelming.
Here is what the default output looks like:
my-site/
├── public/
│ ├── categories/
│ │ ├── category1/index.xml # Generated
│ │ └── ...
│ ├── tags/
│ │ ├── tag1/index.xml # Generated
│ │ └── ...
│ ├── post/
│ │ ├── index.xml # Generated
│ ├── index.xml # The main feed
│ └── ...
For a simple blog, you likely only need the main index.xml at the root. You can control this generation by adding the following to your configuration file:
[outputs]
home = ['html', 'rss']
section = ['html']
taxonomy = ['html']
term = ['html']
In this config, 'html' tells Hugo to generate the web pages, while 'rss' tells it to generate the feed. By only keeping 'rss' in the home array, Hugo will strictly create one RSS file at the root.
If you ever wanted to completely disable RSS on your website, you would use:
disableKinds = ['rss']
Define the number of elements displayed
By examining the default Hugo RSS template, we can see a logic for limits:
...
{{- $limit := .Site.Config.Services.RSS.Limit }}
{{- if ge $limit 1 }}
{{- $pages = $pages | first $limit }}
...
This controls how many posts appear in the feed. By default, all pages are included. To limit the feed to the last n elements, add this to your config.toml:
[services.RSS]
limit = 10
Run your server and check index.xml to verify the limit is applied.
How to change the RSS filename?
By default, the feed is named index.xml. You might want to change this to feed.xml or rss.xml. This is done via the [outputFormats] configuration:
[outputFormats.RSS]
mediatype = "application/rss"
baseName = "feed"
Note: Set baseName to your desired filename without the extension.
Why do this? This is useful for dealing with caching in RSS readers like Feedly. As discussed on Reddit, Feedly caches history. If you deleted old posts but they still appear in Feedly, changing the filename effectively “resets” the feed for new subscribers.
Warning: Changing the filename changes the URL. This will break existing subscriptions. Only do this if you are just starting out or if you have set up a redirect.
Customize the content of the RSS feed
To customize the XML structure, you need to override the default template. Create a file named rss.xml in your layouts/_default/ folder (create the folders if they don’t exist) and paste the content of Hugo’s default rss.xml.
Now you can edit this file to match your needs.
1. Display the full content
By default, Hugo uses a <description> tag containing the first 70 words of your post. If you want subscribers to read the entire article within their RSS reader, replace the description line with:
{{- $content := safeHTML (.Content | html) -}}
<description>{{ $content }}</description>
Alternatively, you can use .Params.Description if you want to use the specific summary defined in your post’s frontmatter.
2. Add a cover image
Visuals engage readers. To display your post’s cover image in the RSS reader, you can inject an HTML <img> tag into the description. Assuming your frontmatter has a cover parameter or you use a standard naming convention:
<description>
{{ "<" | html }}img src="{{ .Permalink }}/cover.jpg" alt="Featured image for {{ .Title }}" {{ "/>" | html}}
{{ $content }}
</description>
3. Better control over the summary
If you prefer to keep a short description but want more control than the automatic 70-word cut, use the manual summary splitter. Add “ inside your Markdown content where you want the preview to stop. Hugo will use everything before this tag as the .Summary.
Change copyright and author details
According to the documentation, you can set feed-wide metadata in your config.toml:
copyright = '© 2023 ABC Widgets, Inc.'
[params.author]
email = "romain@example.com"
name = "Romain Letourneur"
How to add an RSS icon to your theme
Most Hugo themes (like Stack, PaperMod, or Coder) support social icons. Here is the syntax to add the RSS button for hugo-theme-stack:
[[social]]
identifier = "rss"
name = "RSS"
url = "index.xml"
[social.params]
icon = "rss"
Validate your RSS Feed
Since we are manually modifying the XML template, it is crucial to ensure the syntax remains valid. A broken XML file means RSS readers won’t be able to fetch your updates.
Before publishing your changes, build your site locally and copy the content of your public/index.xml. Paste it into the W3C Feed Validation Service. It will highlight any structural errors or encoding issues.
Why optimize your RSS? (The Newsletter connection)
Beyond standard feed readers, a clean RSS feed is the backbone of automated newsletters. Tools like Mailchimp, ConvertKit, or MailerLite have features called “RSS-to-Email”.
By configuring your feed to include the full content and images (as shown above), you can automatically generate and send beautiful email newsletters to your subscribers every time you publish a new article on your Hugo blog, without lifting a finger!
Bonus: Tools for RSS
If you use Google Chrome, the RSS Feed Reader extension is very handy. It renders the raw XML into a readable interface and offers quick subscribe buttons for popular readers like Feedly, Inoreader, or Newsblur.
Personally, I use Feedly to consume content. I appreciate its clean UI, mobile app, and discovery features.