Table of contents
- Quick summary
- Why the feed exists, and why it can vanish
- Step 1: Decide which of the four causes you have
- Step 2: Turn the blog plugin on
- Step 3: Turn feed generation back on
- Step 4: Test a production build, not the dev server
- Step 5: Check `url` and `baseUrl`
- Multiple blogs get multiple feeds
- Verify it worked
- Maintenance
- Ship it, then check the neighbours
Docusaurus is the one platform in this series where the feed usually exists before you ask for it. @docusaurus/preset-classic includes the blog plugin, and the blog plugin writes RSS and Atom files on every production build. So the fix is rarely "add a feed". It is "find out why yours is missing", and there are four causes, each with a one-line repair.
Quick summary
| Check | E5 (Content feed: RSS, Atom or JSON Feed) |
| Platform | Docusaurus 3.x |
| Default | RSS and Atom at /blog/rss.xml and /blog/atom.xml, declared in <head> automatically |
| Four ways it goes missing | Blog plugin disabled, feedOptions.type set to null, checking a dev server, or a wrong url in the config |
| Optional upgrade | type: 'all' adds JSON Feed at /blog/feed.json |
| Time | About 5 minutes |
| Verify | npx aiscan-cli yoursite.com, then curl the feed and grep the <head> |
Why the feed exists, and why it can vanish
The blog plugin does not read your Markdown a second time to build the feed. According to the plugin's own reference page, the feed "works by extracting the build output, and is only active in production". That one sentence explains most support threads about missing feeds: the plugin needs a finished build to read from.
AIScan's survey of 15 live Docusaurus sites, described in the complete Docusaurus setup guide, found 9 serving /blog/rss.xml, and all 9 declared it in <head>. The other 6 are the sites this guide is for. A site with no blog folder has no feed to publish, and a site that switched the plugin off has none either.
Step 1: Decide which of the four causes you have
| Symptom | Cause | Go to |
|---|---|---|
/blog/rss.xml returns 404 on the live site and you have no blog/ folder | You run docs only, or the blog plugin is off | Step 2 |
| The blog exists but the feed 404s | feedOptions.type is null | Step 3 |
The feed works on the live site but 404s on localhost:3000 | You are on docusaurus start, which never builds feeds | Step 4 |
| The feed loads but every link inside points at the wrong host | url in docusaurus.config.js is wrong | Step 5 |
How to know which one: run curl -sI https://yoursite.com/blog/rss.xml. A 200 with application/xml means the feed exists and you only need Step 5 or the head check. A 404 means Steps 2 to 4.
Step 2: Turn the blog plugin on
Docusaurus supports a docs-only mode, documented under Docs > Docs-only mode, where the preset is configured with blog: false. That is a legitimate setup, but it produces no feed at all.
If you want a feed, restore the blog options in docusaurus.config.js:
presets: [
[
'@docusaurus/preset-classic',
{
blog: {
showReadingTime: true,
feedOptions: { type: ['rss', 'atom'] },
},
},
],
],
Then add at least one post under blog/. A blog with zero posts has nothing to syndicate.
If you would rather keep the site docs-only, a feed is not required. Say so in your own notes and accept the E5 warning; a feed with no dated content is worse than no feed.
Step 3: Turn feed generation back on
The reference page states the defaults directly: feedOptions defaults to {type: ['rss', 'atom']}, and "Use null to disable generation". Search your config for type: null and delete it, or set it explicitly:
feedOptions: {
type: 'all',
title: 'Your Site Blog',
description: 'New posts, changelogs and release notes',
copyright: `Copyright © ${new Date().getFullYear()} Your Company`,
limit: 50,
},
Three things in that block matter:
type: 'all'adds JSON Feed at/blog/feed.jsonnext to RSS and Atom. The blog guide lists all three URLs under Docs > Blog > Feed. JSON Feed 1.1 and RFC 4287 (Atom) are the specs the check validates against.limitdefaults to 20 posts. Set it higher, or tonullfor every post, if agents should see your full history.- Author emails. The blog guide states that "RSS feeds require the author's email to be set for the author to appear in the feed". Add
emailto each entry inblog/authors.ymlif you want bylines in RSS.
Step 4: Test a production build, not the dev server
npm run start will never show a feed. Build first, then serve the output:
npm run build
npm run serve
curl -sI http://localhost:3000/blog/rss.xml
The CLI reference lists docusaurus serve as serving your built site locally (default port 3000, output directory build). Expect HTTP/1.1 200 OK and application/xml.
Step 5: Check url and baseUrl
Feed items use absolute links built from the url field in docusaurus.config.js. If url still says https://your-docusaurus-site.example.com or http://localhost, every <link> in the feed points nowhere. Set it to your production origin, with no trailing slash and no path:
url: 'https://yoursite.com',
baseUrl: '/',
Sites deployed under a subpath set baseUrl to something like '/repo-name/', so request the feed at that prefix and confirm it after each deploy.
Multiple blogs get multiple feeds
A site running several blog plugin instances gets one feed per instance. docusaurus.io itself does this: it serves /blog/rss.xml and a separate /changelog/rss.xml, and its <head> declares both, plus a third blog under /tests/blog/. If you run a second instance for release notes, check that each feed is declared and returns 200.
Verify it worked
Lead with the scan. Run npx aiscan-cli yoursite.com and look at check E5, or paste the URL at aiscan.site. By hand, the equivalent is:
curl -s https://yoursite.com/blog/rss.xml | head -c 300
curl -s https://yoursite.com/ | grep -o '<link[^>]*alternate[^>]*>'
Expected output: the first command starts with <?xml version="1.0" and an <rss version="2.0" element with your title inside <channel>. The second prints at least one <link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" ...> tag, plus an Atom tag with application/atom+xml. On docusaurus.io the tags appear on the homepage and on individual blog posts alike, so any page can be your test target.
If it fails: a 404 on the live site after a green build means the deploy served an old build/ directory. Clear the cache with npm run clear, rebuild and redeploy.
Maintenance
Every new post regenerates the feed on the next build, so there is nothing to update by hand. Recheck after upgrading Docusaurus, changing routeBasePath, or adding a second blog instance. The plugin currently ships in version 3.10.2 according to its reference page.
Ship it, then check the neighbours
A feed is the cheapest changed-since-last-week signal a Docusaurus site can publish. Run the scan again, then look at the other rows in the content dimension. The same site probably also needs an llms.txt and an AI-aware robots.txt, since Docusaurus generates neither. The same live-route-versus-generated-file question appears on other platforms, for example Lovable. The full list of checks is at /guides.
Frequently asked questions
What does AIScan's E5 check look for on a Docusaurus site?
It confirms a feed exists at a reachable URL, parses as valid RSS, Atom or JSON Feed, and is declared with a link rel="alternate" tag in the head. Docusaurus's blog plugin does all of that by default in a production build.
Where does Docusaurus publish the feed?
At /blog/rss.xml and /blog/atom.xml by default. Set feedOptions.type to 'all' and it also writes /blog/feed.json. A second blog instance gets its own path, such as /changelog/rss.xml.
My feed returns 404 on localhost but works in production. Is something broken?
No. The plugin's reference page says the feed is extracted from the build output and is only active in production. Run npm run build then npm run serve, and test http://localhost:3000/blog/rss.xml.
The scan says no feed found, and I use docs-only mode. What do I do?
A site configured with blog: false has no blog plugin, so it generates no feed. Either re-enable the blog plugin and publish dated posts, or accept the E5 warning if you have no dated content to syndicate.
Every link in my feed points at localhost or a placeholder domain. How do I fix it?
Set url in docusaurus.config.js to your production origin, without a trailing slash or path, then rebuild and redeploy. Feed items build their absolute links from that value.
My feed only has 20 posts. Can I include more?
Yes. feedOptions.limit defaults to 20. Set it to a larger number, or to null (or false) to include every post, then rebuild.
Authors are missing from my RSS items. Why?
The Docusaurus blog guide says RSS feeds require the author's email to be set for the author to appear. Add an email field to each author in blog/authors.yml.
Do I need to add the link tag to the head myself?
No. The blog plugin injects the rel="alternate" tags for each generated feed type. Only add your own tags if you serve a feed the plugin does not generate.
Related guides
How to publish an RSS/Atom/JSON feed and declare it in the head on Replit
A Replit app can serve /feed.xml two completely different ways, and which one applies to you depends on a setting you may never have opened. Get it backwards and you'll ship a feed that 404s in…
How to publish an RSS/Atom/JSON feed and declare it in the head on Lovable
A sitemap tells a crawler what exists. It does not tell an agent what changed since last week, and that gap is what check E5 grades: whether the site publishes a dated content feed at all. Run…
Add an RSS Feed AI Agents Can Actually Find
Two staticsite generators build you a feed with zero configuration. One declares it in <head on every site we tested. The other only manages it on five of every eight. Same defaulton feature, same…
The complete AI readiness setup for Docusaurus in 2026
Docusaurus is the framework most likely to be sitting between an AI agent and the answer it is looking for. It runs a very large share of the developer documentation on the web, and developer…
