Textless dark-green cover with concentric mint and coral arcs on the right for a live feed and a faint block grid in the corner, with negative space on the left.
Textless dark-green cover with concentric mint and coral arcs on the right for a live feed and a faint block grid in the corner, with negative space on the left.
AI Readiness

How to publish an RSS/Atom/JSON feed and declare it in the head on Docusaurus

Docusaurus writes RSS and Atom by default, but four setups lose the feed. Find yours, restore it, add JSON Feed and verify with AIScan check E5.

AAsif Rahman 29 Sept 2026 6 min read
#Docusaurus#RSS#Atom#JSON Feed#feedOptions#blog plugin

This guide covers E5 · Content.

Table of contents

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

CheckE5 (Content feed: RSS, Atom or JSON Feed)
PlatformDocusaurus 3.x
DefaultRSS and Atom at /blog/rss.xml and /blog/atom.xml, declared in <head> automatically
Four ways it goes missingBlog plugin disabled, feedOptions.type set to null, checking a dev server, or a wrong url in the config
Optional upgradetype: 'all' adds JSON Feed at /blog/feed.json
TimeAbout 5 minutes
Verifynpx 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

SymptomCauseGo to
/blog/rss.xml returns 404 on the live site and you have no blog/ folderYou run docs only, or the blog plugin is offStep 2
The blog exists but the feed 404sfeedOptions.type is nullStep 3
The feed works on the live site but 404s on localhost:3000You are on docusaurus start, which never builds feedsStep 4
The feed loads but every link inside points at the wrong hosturl in docusaurus.config.js is wrongStep 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.json next 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.
  • limit defaults to 20 posts. Set it higher, or to null for 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 email to each entry in blog/authors.yml if 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