pagination
Skill4 starsChanged 4 months agoMITView on GitHub
Page large API collections predictably — choose offset versus cursor pagination, expose navigation links, and enforce sane page-size limits so responses stay bounded and stable under concurrent writes. Use when the user needs to expose next/previous page navigation and page-size limits in an API response; the user must choose between offset/limit and cursor-based pagination for an API collection; the user needs to return a large collection from an API in pages rather than all at once. Keywords: api, pagination, cursor, offset, limits, links.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
- Pradnyeshp/Claude-Skillstheir own version, first seen Jul 6, 2026
- ffsshhttiikk/opencode-agents-skillstheir own version, first seen Feb 28, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- ffsshhttiikk/opencode-agents-skills★ 2same name
- Pradnyeshp/Claude-Skills★ 2same name
- jars-demo/jars-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository119 other files it gives its agents.
- strategy-bitrix-d7-incrementalSkill
- strategy-explicit-over-magicSkill
- strategy-framework-conventionsSkill
- strategy-legacy-safe-editsSkill
- strategy-minimal-diffSkill
- strategy-no-untested-refactorSkill
- strategy-preserve-public-apiSkill
- strategy-readonly-immutabilitySkill
- strategy-security-firstSkill
- strategy-test-drivenSkill
- openapiSkill
- rest-designSkill
- versioningSkill
- cqrsSkill
- dependency-inversionSkill
- hexagonalSkill
- repository-patternSkill
- service-layerSkill
- bitrixSkill
- findings-reportSkill
- laravelSkill
- performanceSkill
- phpSkill
- project-analysisSkill
- refactoringSkill
- roi-prioritizationSkill
- securitySkill
- stack-detectionSkill
- cache-layersSkill
- component-engineSkill
- d7-eventsSkill
- d7-loaderSkill
- d7-orm-queriesSkill
- iblock-elementsSkill
- kernel-main-moduleSkill
- localizationSkill
- controllersSkill
- ormSkill
- validationSkill
- controllersSkill
- query-builderSkill
- routingSkill
- autoload-psr4Skill
- dependency-managementSkill
- scriptsSkill
- connection-poolingSkill
- mysql-indexingSkill
- redisSkill
- transactionsSkill
- ci-github-actionsSkill
- deployment-strategiesSkill
- docker-phpSkill
- env-configSkill
- associationsSkill
- entities-mappingSkill
- orm-basicsSkill
- entity-apiSkill
- module-developmentSkill
- routing-controllersSkill
- formsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
3 rules. 0 are common, 3 are distinctive, and 0 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 63
Do not page a full bulk export where the client wants every row.
- Distinctive: line 64
Do not paginate a collection that is inherently small and bounded, such as a fixed list of a user's roles or a handful of settings.
- Distinctive: line 88
Do not compute an exact total count on every page request
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- generated: do not edit — source: knowledge/atoms/api/pagination/ --><!-- schema: atomVersion=3 skillVersion=2 graphVersion=1 --><!-- compile: @php-skills/compiler v1.0.0 (deterministic build) -->API Pagination
When to use
- The user needs to expose next/previous page navigation and page-size limits in an API response.
- The user must choose between offset/limit and cursor-based pagination for an API collection.
- The user needs to return a large collection from an API in pages rather than all at once.
When NOT to use
- Do not page a full bulk export where the client wants every row; stream the response or provide an async export job instead.
- Do not paginate a collection that is inherently small and bounded, such as a fixed list of a user's roles or a handful of settings.
Core guidance
- Prefer cursor pagination for deep or fast-changing data — Use cursor (keyset) pagination — a cursor pointing at the last seen sort key — for large, deep, or frequently changing collections. Reserve offset/limit for small datasets or when clients need to jump to an arbitrary page number.
- Enforce a default and maximum page size — Apply a sensible default page size (for example 20) and clamp the client-supplied
size to a hard maximum (for example 100). Reject or cap oversized requests rather
than honoring an unbounded
per_page.
Quick recipe
- Choose a stable, unique, indexed sort key (for example
idorcreated_at, id), read the requested page size, and clamp it to the server maximum. (verify: The chosen key is indexed and unique, and an oversized page-size request is capped.) - Decode the incoming cursor to the last seen key value and query
WHERE (sort_key) > :cursor ORDER BY sort_key LIMIT :size + 1, fetching one extra row to detect whether more pages exist. (verify: The query seeks by the indexed key and the extra row correctly indicates has_more.) - Return the page items plus a consistent meta block — the next cursor (encoded
from the last item), a
has_moreflag, and a ready-to-follownextlink. (verify: Following the returned next link fetches the subsequent page with no gaps or duplicates.)
Best practices
- Do not compute an exact total count on every page request
- Include ready-to-follow
next(andprev/firstwhere meaningful) links or the next cursor in the response, so clients follow links rather than constructing page URLs themselves - Order pages by a stable, unique key (or a composite ending in the primary key) that is indexed, and derive the cursor from it
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| Running an exact total COUNT on every page | The COUNT over a large filtered set can cost as much as the page query, doubling load for a number most clients never use. | Omit the total, cache it, or return a has_more flag; compute an exact count only when the client explicitly asks. |
| A different pagination envelope per endpoint | Clients must special-case every route, and shared pagination helpers become impossible to reuse. | Standardize one envelope (data plus a consistent meta/links block) and apply it across all paginated endpoints. |
| Calling an offset page number a cursor | It inherits every offset weakness (drift, deep-page cost) while implying keyset guarantees the client does not actually get. | Base a real cursor on the last row's stable sort-key value so paging seeks by index, not by counting rows. |
See references/anti-patterns.md.
Common mistakes
- Deep offsets get progressively slower — A query like
LIMIT 20 OFFSET 100000still scans and discards the first 100000 rows before returning the page. Fix: Switch deep pagination to keyset/cursor so each page seeks directly to the next range via an index. - Offset pagination skips or repeats rows under writes — With offset/limit, a row inserted or deleted between page requests shifts the window, so clients skip or see duplicate items. Fix: Use cursor (keyset) pagination anchored on a stable key so the next page continues from the last seen item regardless of inserts.
- Honoring an unbounded client page size — Trusting the client's
per_pagewithout a cap lets?per_page=1000000pull the whole table in one response. Fix: Clamp the requested size to a hard maximum server-side and document the ceiling.
Version notes
- The Link header format is standardized by RFC 8288 (PHP >=8.1) — When returning pagination links in the HTTP
Linkheader, use the RFC 8288 web linking format withrel="next"andrel="prev"; the same relations also work inside a JSON links block.
Security
- Keep cursors opaque and scoped to the caller — Validate the decoded cursor as untrusted input and re-apply the caller's authorization filter (tenant, owner) to every page, so a forged or swapped cursor cannot page into another user's records or crash the decoder.
Testing
- Activation and decision behavior are verified in
eval/scenarios/api/pagination.yaml.
Additional resources
- references/anti-patterns.md
- references/core.md
- references/examples.md
- references/pitfalls.md
- references/recipes.md
- references/version-differences.md
Knowledge graph
Related: api/openapi, api/rest-design, security/sql-injection-prevention
<!-- graph-fragment: graph/fragments/api/pagination.yaml -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

