Pagination First
List endpoints (GET /collection) MUST return paginated responses with: (1) a default page size (commonly 20–50, never unbounded); (2) a maximum page size enforced server-side (e.g.…
$ prime install @community/principle-pagination-first Projection
Always in _index.xml · the agent never has to ask for this.
PaginationFirst [principle] v1.0.0
Every list endpoint must paginate from day one. Adding pagination to an unbounded endpoint after launch is a breaking change that requires every client to update; defaulting to a hard cap (e.g. 50 items) future-proofs the API at zero cost on day one.
List endpoints (GET /collection) MUST return paginated responses with: (1) a default page size (commonly 20–50, never unbounded); (2) a maximum page size enforced server-side (e.g. 100); (3) explicit pagination metadata in the response body (cursor or next/prev links); (4) links following RFC 5988 Web Linking conventions OR the JSON:API pagination object. Clients that pass
?page_size=10000get 100 (capped) and anextcursor. The contract is established before any list endpoint ships; retrofitting pagination requires a new version (v2) and a migration window.
Loaded when retrieval picks the atom as adjacent / supporting.
PaginationFirst [principle] v1.0.0
Every list endpoint must paginate from day one. Adding pagination to an unbounded endpoint after launch is a breaking change that requires every client to update; defaulting to a hard cap (e.g. 50 items) future-proofs the API at zero cost on day one.
List endpoints (GET /collection) MUST return paginated responses with: (1) a default page size (commonly 20–50, never unbounded); (2) a maximum page size enforced server-side (e.g. 100); (3) explicit pagination metadata in the response body (cursor or next/prev links); (4) links following RFC 5988 Web Linking conventions OR the JSON:API pagination object. Clients that pass
?page_size=10000get 100 (capped) and anextcursor. The contract is established before any list endpoint ships; retrofitting pagination requires a new version (v2) and a migration window.
Attributed To
Mark Nottingham, 'Web API Versioning' (RFC 9170-related); GitHub API, Stripe API, Twitter API design conventions; JSON:API specification.
Applies To
- All collection endpoints (GET /users, GET /orders, GET /comments)
- Search endpoints (GET /search?q=...)
- Filtered subresources (GET /users/{id}/sessions)
- Webhook event lists, audit logs, transaction histories — high-cardinality time-series
- Internal admin tools that read production tables
Counter Examples
- GET /users returns a single JSON array of all 50,000 users. Client OOMs on page load; database query takes 12 seconds; cache TTL collapses.
- Pagination added later as
?page=2— old clients still pass no page parameter and get a different (now first 100) result; existing UI silently shows truncated data without indication. ?limitis honored but nonextcursor returned — clients implement manual offset (?limit=100&offset=200); offset pagination breaks under concurrent inserts (skips/duplicates rows).
Loaded when retrieval picks the atom as a focal / direct hit.
PaginationFirst [principle] v1.0.0
Every list endpoint must paginate from day one. Adding pagination to an unbounded endpoint after launch is a breaking change that requires every client to update; defaulting to a hard cap (e.g. 50 items) future-proofs the API at zero cost on day one.
List endpoints (GET /collection) MUST return paginated responses with: (1) a default page size (commonly 20–50, never unbounded); (2) a maximum page size enforced server-side (e.g. 100); (3) explicit pagination metadata in the response body (cursor or next/prev links); (4) links following RFC 5988 Web Linking conventions OR the JSON:API pagination object. Clients that pass
?page_size=10000get 100 (capped) and anextcursor. The contract is established before any list endpoint ships; retrofitting pagination requires a new version (v2) and a migration window.
Attributed To
Mark Nottingham, 'Web API Versioning' (RFC 9170-related); GitHub API, Stripe API, Twitter API design conventions; JSON:API specification.
Applies To
- All collection endpoints (GET /users, GET /orders, GET /comments)
- Search endpoints (GET /search?q=...)
- Filtered subresources (GET /users/{id}/sessions)
- Webhook event lists, audit logs, transaction histories — high-cardinality time-series
- Internal admin tools that read production tables
Counter Examples
- GET /users returns a single JSON array of all 50,000 users. Client OOMs on page load; database query takes 12 seconds; cache TTL collapses.
- Pagination added later as
?page=2— old clients still pass no page parameter and get a different (now first 100) result; existing UI silently shows truncated data without indication. ?limitis honored but nonextcursor returned — clients implement manual offset (?limit=100&offset=200); offset pagination breaks under concurrent inserts (skips/duplicates rows).
Sources
Examples
- Stripe: GET /v1/charges?limit=10&starting_after=ch_abc123 → response includes
has_more: true+ the last item's id is the next cursor. - GitHub: GET /repos/{owner}/{repo}/issues → Link header:
<https://api.github.com/...?page=3>; rel='next', <...?page=10>; rel='last'. Default per_page=30, max=100. - Linear API: GraphQL connection pattern —
issues(first: 50, after: '...') { edges { node { ... } } pageInfo { hasNextPage endCursor } }. - JSON:API:
{ data: [...], links: { next: '...', prev: '...', first: '...', last: '...' }, meta: { total: 1234 } }.
Relations
requires: @community/pattern-cursor-pagination
Source
- RFC 5988 — 'Web Linking' (Mark Nottingham, October 2010) — Link header for next/prev/last
- JSON:API specification — pagination meta + links objects
- GitHub REST API documentation — cursor and page-based pagination examples
- Stripe API reference — cursor-based pagination with
starting_after/ending_before - Phil Sturgeon, 'Build APIs You Won't Hate' — pagination chapter
Requires
@community/pattern-cursor-pagination
Source
prime-system/examples/frontend-design/primes/compiled/@community/principle-pagination-first/atom.yaml