Choosing a feed format: RSS 2.0, Atom and JSON Feed

The audience decides the format: readers and podcasts need RSS, Atom is stricter and date-safe, and JSON Feed is easiest for modern clients.

What each format is good at

RSS 2.0AtomJSON Feed
SpecificationHarvard/UserLand, loosely specifiedRFC 4287, a formal standardCommunity spec, two versions
MaturityUniversal reader supportUniversal, but rarely chosen firstModern readers and applications
DatesRFC 822, easily malformedRFC 3339, unambiguous, timezone requiredRFC 3339
Identifiersguid, often omittedid, required, must be a URIid, required
Contentdescription only, plus content:encoded extensionNative rich content with type and languageNative content_html and content_text
Podcast supportRequired by every podcast directoryEssentially unused in podcastingNot supported
Escaping strictnessVery tolerant, hence very brokenStrict XML, so errors are caughtJSON, so no escaping of markup
{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Release Notes",
  "home_page_url": "https://example.com/releases",
  "feed_url": "https://example.com/feed.json",
  "language": "en-GB",
  "authors": [{ "name": "Platform Team", "url": "https://example.com/team" }],
  "items": [
    {
      "id": "https://example.com/releases/2026-09-platform-3-2",
      "url": "https://example.com/releases/2026-09-platform-3-2",
      "title": "Platform 3.2",
      "content_html": "<p>Streaming transforms and faster cold start.</p>",
      "date_published": "2026-09-18T09:00:00+01:00",
      "tags": ["platform", "release"]
    }
  ]
}
  • Podcasts must be RSS 2.0, because the directory ecosystem reads the Apple and Podcasting 2.0 namespaces and nothing else.
  • Atom is the right choice if you want a strict parser to catch your own escaping mistakes at build time.
  • JSON Feed is the easiest to generate from a modern application, because your template engine does the escaping.
  • Publishing all three is cheap: one internal item model, three serialisers.

One item model, several serialisers

from dataclasses import dataclass
from datetime import datetime

@dataclass
class Item:
    id: str                      # stable URI, never changes
    title: str
    url: str
    summary: str                 # short, plain text
    html: str                    # full content, trusted HTML
    published: datetime          # timezone aware
    updated: datetime | None = None
    author: str | None = None
    tags: tuple[str, ...] = ()

# The model is the contract. Only the serialisation differs per format, which is
# what keeps three feeds from drifting apart.
<!-- Atom benefit in practice: the date is unambiguous and required -->
<entry>
  <id>https://example.com/releases/2026-09-platform-3-2</id>
  <title>Platform 3.2</title>
  <updated>2026-09-18T09:00:00+01:00</updated>
  <author><name>Platform Team</name></author>
  <link rel="alternate" href="https://example.com/releases/2026-09-platform-3-2"/>
  <summary>Streaming transforms and faster cold start.</summary>
  <content type="html">&lt;p&gt;Streaming transforms and faster cold start.&lt;/p&gt;</content>
</entry>
💡
Whatever you choose, the item identifier must be stable for the life of the item. It is the only thing a reader uses to decide whether it has already shown the item, so changing it re-notifies every subscriber.

FAQ

Should I publish RSS and Atom from the same URL?
No. Serve each format from its own URL and declare both from the page head, so a reader can pick. Content negotiation on one URL with Vary: Accept also works but confuses feed validators.
Is JSON Feed worth publishing if my audience uses RSS readers?
Only if you also have applications that consume it. For a blog, RSS plus Atom covers everything; JSON Feed is for your own tooling and modern clients.

The RSS 2.0 feed format Migrating between RSS, Atom and JSON Feed

Last refreshed 2026-09-18.