Hugo RSS and Atom Feeds

Page content

RSS and Atom are still how a lot of readers and tools discover new posts. Hugo can emit both from the same content tree. On DevOpsTales the site ships classic RSS plus Atom via the hugo-atom-feed component theme, with a custom Atom template that skips the filedir partial section.

Hugo

Enable RSS and Atom outputs

In config.toml, assign formats per page kind. Home and section pages get both feeds; individual posts stay on HTML (plus any other formats you add):

theme = ["hugo-atom-feed", "hugo-dynamic-tabs", "roadster"]

[outputs]
  home    = ["HTML", "RSS", "ATOM", "llms", "WebManifest"]
  section = ["HTML", "RSS", "ATOM"]
  page    = ["HTML", "markdown"]

Putting hugo-atom-feed in the theme list registers the Atom media type and output format. Roadster (or your UI theme) still owns the HTML chrome.

After hugo, you typically get:

  • Site RSS: /index.xml (Hugo’s default RSS basename)
  • Site Atom: /atom.xml
  • Per-section feeds under each section URL

Exact paths follow your baseURL and pretty-URL settings. On this site that means URLs under https://devopstales.github.io/.

Why customize Atom

The stock Atom theme is a good start. This blog also keeps HTML fragments under content/filedir/ for series includes. Those files are not articles. They should not pollute /atom.xml or invent a useless section feed.

Two layers handle that:

  1. A site param listing sections to treat carefully:
[Params]
  disable_atom_sections = ["filedir"]
  1. A site override of layouts/_default/list.atom.xml that returns early for that section:
{{- if eq .Section "filedir" -}}
{{/* Skip atom feed for filedir section */}}
{{- else -}}
<feed xmlns="http://www.w3.org/2005/Atom"{{ with site.Language.Locale }} xml:lang="{{ . }}"{{ end }}>
  ...
</feed>
{{- end -}}

Inside the feed, entries are limited to types in mainSections (or feedSections if you set it), and pages with disable_feed: true are dropped:

{{- $feed_sections := site.Params.feedSections | default site.Params.mainSections -}}
{{- $pages := where .Pages "Type" "in" $feed_sections -}}
{{- $pages = where $pages ".Params.disable_feed" "!=" true -}}

That keeps Atom aligned with the “real” blog sections (ai, kubernetes, kubernetes, hugo, and so on) instead of every directory under content/.

RSS override

RSS uses Hugo’s familiar channel/item shape. This site overrides layouts/_default/rss.xml so summaries prefer the page summary (from the body / <!--more-->) and can attach a thumbnail enclosure when thumbnail is set in front matter.

Per-post opt-out for RSS:

rss_ignore: true

Use that sparingly for pages that must exist in HTML but should not show up in feed readers.

Verify

hugo

curl -sI https://devopstales.github.io/atom.xml | head
curl -s https://devopstales.github.io/atom.xml | head -n 40

curl -sI https://devopstales.github.io/index.xml | head
curl -s https://devopstales.github.io/kubernetes/atom.xml | head -n 20

Confirm filedir does not get a useful Atom listing, and that new sections you care about (including hugo) appear in mainsections so they are eligible for feed entries.

You can also paste the Atom URL into the W3C Feed Validation Service.

Summary

Enable RSS and ATOM on home and section outputs, add hugo-atom-feed as a component theme, then override Atom (and RSS if needed) so partial content directories like filedir stay out of reader inboxes. The result is boring in the best way: stable feed URLs that track your real posts.