← ClaudeAtlas

api-paginationlisted

Implement correct, fast API pagination — cursor vs offset trade-offs, opaque cursor encoding, stable sort keys, page-size limits, total-count costs, and consumer-side iteration that survives inserts, deletes, and retries. With runnable cursor checks.
vanara-agents/skills · ★ 7 · Code & Development · score 77
Install: claude install-skill vanara-agents/skills
# API Pagination Pagination looks trivial until data changes underneath the reader. Offset pagination silently **skips or duplicates rows** when inserts land mid-iteration; cursor pagination survives churn but demands a stable sort key and an opaque token contract. This skill covers both sides: designing the API and consuming one correctly. Deep detail lives in `references/`; copy-paste material in `examples/`; a runnable cursor round-trip check in `scripts/`. ## Decision: offset vs cursor | Situation | Use | |---|---| | Admin tables, small datasets, "jump to page 7" required | Offset (`LIMIT/OFFSET`) | | Feeds, sync endpoints, anything users scroll | Cursor (keyset) | | Data changes while clients iterate | Cursor — offset will skip/duplicate | | Deep pages (offset > ~10k rows) | Cursor — `OFFSET n` scans and discards n rows | Offset's failure mode is correctness, not just speed: a row inserted before your current position shifts everything, so page 3 re-shows an item from page 2 (duplicate) or swallows one (skip). ## Keyset mechanics (the part people get wrong) The sort key must be **unique and immutable**. `created_at` alone is not unique — two rows with the same timestamp make the cursor ambiguous and rows vanish. Always add a tiebreaker: ```sql -- WHERE clause for "next page after (2026-07-01T12:00:00Z, id 4711)" descending SELECT * FROM items WHERE (created_at, id) < ('2026-07-01T12:00:00Z', 4711) ORDER BY created_at DESC, id DESC LIMIT 51; -- page_size + 1 to de