Short answer: Headless CMSs such as Contentful, Sanity, Strapi or Storyblok store content and expose it through an API, but they do not usually publish an RSS feed for your site. The feed is built in your front end: either at build time as a static file, or in a server route that fetches the latest entries from the CMS API, renders RSS or Atom, and caches the result. Map each entry to a title, absolute URL, permanent ID, date and summary, rebuild or purge on publish through a webhook, and advertise the feed in your layout.
Headless architecture separates content management from presentation. Editors work in the CMS; developers build the website with a framework such as Next.js, Nuxt, Astro, Gatsby or SvelteKit, fetching content through an API. It is a flexible model, but it quietly removes something that traditional CMSs gave for free: the feed. Many headless sites launch without RSS, and readers, newsletter tools and partners are left without a way to follow them. Adding a feed is not hard, but a few decisions determine whether it will be reliable.
Why the CMS does not publish the feed
A traditional CMS knows your URLs, templates and site structure, so it can generate a feed that matches your pages. A headless CMS knows only the content. It does not know that an entry of type “article” with slug “hello-world” lives at https://example.com/blog/hello-world/, what your site is called, or which entries should be public. That knowledge lives in the front end, so the front end is the natural place to build the feed.
This is also why a feed generated by a separate script, disconnected from the site’s routing, tends to drift: when someone changes a route, the feed keeps pointing at the old pattern. Some headless platforms and plugins can output RSS-like data or webhook payloads, and a few community extensions generate feeds, but relying on the front end keeps URLs, filtering and presentation consistent with your actual site.
Two ways to generate the feed
| Approach | Jak to funguje | Best for | Watch out for |
|---|---|---|---|
| Build time | During the static build, fetch entries and write feed.xml | Static and mostly static sites | Feed updates only when the site rebuilds |
| Server route | An endpoint fetches entries on request, renders the feed and caches it | Sites with server rendering or frequent updates | API load and latency without caching |
Both are valid. If your site is already rebuilt on every publish through a webhook, build time is simplest and fastest: the feed is a file. If the site renders on the server or uses incremental regeneration, a cached route keeps the feed fresh without full rebuilds.
Prepare the content model for feeds
A feed is only as good as the fields behind it, and headless content models are designed by developers who may not have thought about feeds. A few small additions make a big difference:
- A publish date field that editors control, separate from system timestamps.
- An excerpt or summary field, required for articles, with a sensible length limit.
- A featured image field with alt text, used both for the page and the feed.
- A “show in feed” flag, if some entries should appear on the site but not in the feed, such as sponsored or internal posts.
- Stable slugs, with a policy that published slugs change only with a redirect.
Adding these fields early is far easier than retrofitting them after hundreds of entries exist. They also improve other outputs, such as social previews and sitemaps, which rely on the same information.
Mapping CMS fields to feed elements
Decide once how each feed element is filled, and document it:
- Title: the entry’s title field.
- Link: your site’s base URL plus the route pattern and slug, for example
/blog/{slug}/. Build it with the same function your site uses for links, so they never diverge. - ID or guid: the CMS entry ID combined with your domain, or the canonical URL if slugs never change. The entry ID is safer, because editors do change slugs.
- Date: a dedicated “publish date” field, not the system’s “updated at” timestamp, which changes with every edit and would reorder the feed.
- Summary: an excerpt field; if none exists, add one to the content model rather than truncating body text.
- Full content: rendered from rich text or structured blocks to clean HTML with absolute URLs.
- Image: the hero or featured image, converted to an absolute URL at a sensible size through the CMS’s image API.
- Author and categories: from references, if your model has them.
Rendering rich text safely
Headless CMSs often store body content as structured rich text or blocks rather than HTML. For a full-text feed you must render it to HTML, just as your pages do, but simpler:
- Output headings, paragraphs, lists, links, images and quotes as plain HTML without classes.
- Convert embedded components, such as carousels or calculators, into a link or a short note, because readers cannot run them.
- Make every link and image URL absolute.
- Escape or wrap the HTML correctly for XML; a feed library handles this for you.
If rendering full text is complicated, start with a summary feed. It is valid, useful and easy to extend later.
Keeping the feed fresh
Most headless CMSs can send a webhook when content is published, updated or deleted. Use it:
- For build-time feeds, trigger a site rebuild or a partial rebuild that regenerates the feed.
- For server-route feeds, purge the feed’s cache entry, or rely on a short cache time of a few minutes.
- Handle scheduled publishing: if the CMS publishes entries at a future time, make sure a webhook or scheduled rebuild runs then.
Filter out drafts, previews and unpublished entries explicitly in the feed query. Preview tokens used by your editors must never be used when generating the public feed.
Performance and API limits
- Fetch only what you need: the latest 20 to 50 entries and the fields the feed uses.
- Cache the rendered feed, not just the API response, so repeated requests from readers do not hit the CMS.
- Send ETag and Last-Modified headers so readers can make cheap conditional requests.
- Mind rate limits: many headless CMSs limit API calls per second or per month. An uncached feed route polled by many readers can consume a surprising share.
Testing before launch
- Generate the feed in a preview or staging environment and run it through a validator.
- Compare three items with their pages: titles, URLs, dates and images must match exactly.
- Publish, edit and unpublish a test entry in the CMS and confirm the feed follows each change within your cache time.
- Check that drafts and scheduled entries never appear early.
- Add the production feed to a reader and a newsletter tool, and look at how items render there.
Repeat the test when the content model changes. Renamed fields are the most common reason a headless feed suddenly shows empty summaries or missing images, because the feed code still reads the old field name.
Framework-specific notes
Most modern frameworks make the route easy. Astro has the @astrojs/rss package for an endpoint. Next.js and Nuxt can serve a feed from a route handler or server route that returns XML with the right content type. Gatsby and Eleventy have feed plugins that run at build time. Whichever you use, set the production site URL in configuration, return application/rss+xml or application/xml, and add a link rel="alternate" to your root layout so every page advertises the feed.
If you need a feed for a headless site you do not control, or want to combine it with other sources before it reaches your tools, our tool, Feeds, creates feeds from public pages that list articles and can use a site’s structured article data when it is present. It also merges several sources into one filtered feed. Try it from the home page.
Related reading
- Adding RSS to a Static Site: Hugo, Jekyll, Eleventy and Astro
- Anatomy of an RSS 2.0 Feed: Every Element Explained
- How to Serve an RSS Feed Correctly: Headers, Caching and CDNs
The bottom line
In a headless setup, the feed belongs in the front end, where URLs and site knowledge live. Generate it at build time or in a cached server route, map CMS fields carefully to title, absolute link, permanent ID, publish date, summary and image, trigger rebuilds or purges with webhooks, and advertise the feed in your layout. With those pieces in place, a headless site can offer a feed as reliable as any traditional CMS.
FAQ
Do headless CMSs have RSS feeds?
Usually not for your website. They expose content through APIs, and the front end must generate the feed because it knows your URLs and site structure.
Should I generate the feed at build time or on request?
Build time is simplest for static sites that rebuild on publish. A cached server route suits sites with server rendering or frequent updates. Both produce the same feed.
Which date field should the feed use?
A dedicated publish date field. System timestamps such as updatedAt change with every edit, which would reorder the feed and make old items look new.
What should I use as the item guid?
The CMS entry ID combined with your domain is the safest choice, because it never changes even when editors change the slug or title.
How do I keep the feed up to date?
Use the CMS’s publish webhook to rebuild the site or purge the feed cache, and make sure scheduled entries trigger an update when they go live.


