Adding RFC 5005 Paging to an Atom 1.0 Feed Without Breaking Entry Identity
A practical guide to paging an Atom 1.0 feed with RFC 5005 link relations, stable timestamp-plus-ID cursors, and validation checks that preserve entry identity across pages.
25 Sept 2026, 08:38 UTC

The Problem: Large Feeds Break Reader Traversal
A feed that once held fifty entries can grow to thousands. When the entire history ships in a single Atom 1.0 document, readers download megabytes of XML to see the newest item, and server response times climb. The useful takeaway is that you can split the feed into pages using the link relations defined in RFC 5005 (Feed Paging and Archiving) while keeping every page a valid Atom 1.0 document and preserving stable entry IDs across pages and redeployments.
Desired Outcome: Pageable Atom 1.0 with Stable Identity
The goal is a set of paginated documents that behave as one logical feed. Readers can move forward and backward through history, but every page remains a complete, valid Atom 1.0 document. Entry identifiers do not change when a page number changes, when the page size changes, or when the application is redeployed.
- Each page is well-formed XML in the Atom 1.0 namespace.
- Feed-level
<id>is identical on every page. - Entry
<id>values are stable and unique across the full archive. - Paging links appear only when the target page exists.
- The first page remains useful even if a client ignores all paging links.
Prerequisites: What Your Feed Must Already Have
Before adding paging links, confirm the following foundations. Without them, paging will introduce duplicates, gaps, or invalid documents.
- An existing Atom 1.0 feed. The namespace must be
http://www.w3.org/2005/Atom. Atom 0.3 uses a different namespace and required element set; do not mix the two in one document. - Deterministic newest-first ordering with a unique tiebreaker. If two entries share the same publish timestamp, the sort order must fall back to a unique field such as the entry ID so the sequence never changes.
- Stable per-entry IDs. Use a permanent identifier such as a tag URI or UUID. Do not derive the ID from the page number, database row number, or current URL.
- Server-side pagination and retained storage. The application must be able to query a specific slice of entries and must keep older entries available for later pages.
- A fixed page size treated as a published contract. Changing the page size later can break crawlers and cached pages. If the size must change, version the endpoint (for example,
/v2/feed) rather than altering the existing URLs.
Procedure: Adding Feed Paging Links
Choose a Stable Cursor, Not Feed-Level updated
Derive page boundaries from a stable cursor such as a monotonic publish timestamp combined with the entry ID. Do not use the feed-level <updated> timestamp as a cursor. That value changes whenever any entry is added or modified, which can cause entries to be skipped or repeated when a new item is published between two page requests.
Emit Self and Paging Links on Every Page
Every page must include a rel="self" link that describes the current page URL. Add first, last, previous, and next links only when the corresponding page exists. The feed-level <id> stays the same on all pages so consumers recognize the pages as one feed.
| Link relation | Meaning | When to include |
|---|---|---|
rel="self" | URL of the current page | Always |
rel="first" | First page in the sequence | When page 1 exists and the current page is not page 1 |
rel="last" | Last page in the sequence | When the final page exists and the current page is not the final page |
rel="previous" | Page immediately before the current one | When a previous page exists |
rel="next" | Page immediately after the current one | When a next page exists |
The following XML fragment is illustrative and shows the link structure for a first page that has a next page and a known last page. It is not output from a tested system.
<feed xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<title>Example Feed</title>
<updated>2026-11-12T00:00:00Z</updated>
<link rel="self" href="https://example.com/feed?page=1"/>
<link rel="next" href="https://example.com/feed?page=2"/>
<link rel="last" href="https://example.com/feed?page=42"/>
<!-- entries for page 1 -->
</feed>
Serve the Correct Media Type and Cache per Page URL
Serve every page with the Atom XML media type application/atom+xml, not a generic HTML or plain-text type. Caching headers and conditional requests (ETag, Last-Modified) must be keyed to the exact page URL. If a cache key ignores the page parameter, a client may receive page 1 content when it requested page 3.
Expected Checks: Validating Pages and Boundaries
Verification should cover XML validity, HTTP behavior, and logical continuity across the page chain.
XML and Atom Validation
Run a general XML parser and an Atom-aware validator against representative pages. On a build server or CI runner with read access to the generated files, a basic well-formedness check can be run locally:
xmllint --noout /path/to/page1.atom
Placeholder: /path/to/page1.atom is the generated page file. Expected check: the command exits with status 0 and prints no parse errors. Risk: xmllint without a schema checks well-formedness only; it does not confirm that required Atom elements or link relations are semantically correct.
HTTP and Media Type Check
From any HTTP client with network access, request a page and inspect the status and content type:
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" "https://example.com/feed?page=1"
Placeholder: https://example.com/feed?page=1 is the page URL. Expected check: HTTP 200 and application/atom+xml. Risk: redirects, authentication, or CDN rules may mask the origin media type.
Crawl the Full Chain
Follow next links from the first page to the last and collect every entry <id>. Compare the set against stored entries. Check for duplicates, gaps, and correct previous/next targets. Test boundary cases explicitly: an empty archive, a single entry, exactly one full page, one entry beyond a full page, and a new entry published between two page requests.
Stability Across Redeploys
Confirm that the feed-level <id> and entry <id> values are unchanged across pages and after a redeploy. If paging is disabled, the unpaged fallback feed must remain valid Atom 1.0 with the same feed-level ID.
Recovery Options: Falling Back Safely
If navigation links are wrong or boundaries shift unexpectedly, stop serving the paged chain and fall back to the last known-good feed or a complete unpaged feed. Preserve previously published entry IDs so consumers do not treat old items as new. Log the page cursor and the entry-ID range for each request so the failure can be reproduced.
Because enabling paging changes the served documents, a rollback path is required. Revert to the previous unpaged feed generation code or route the endpoint back to the unpaged handler. Do not delete or renumber entry IDs during recovery.
Limitations and Reader Behavior
Feed-paging link relations are advisory. Many readers follow only self and next, or ignore paging entirely, so the first page must contain the newest entries and remain useful on its own. Changing the page size or ordering key after publication can break crawlers and cached pages; treat both as a versioned contract. Feed-level <updated> timestamps are not reliable pagination cursors, and inconsistent per-page timestamps can confuse consumers that expect feed-wide freshness. Atom 0.3 and Atom 1.0 differ in required elements and namespace; never mix their element sets in one document.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.