laravel-json-api/cursor-pagination
Cursor-based pagination for Laravel JSON:API. Adds a cursor paginator so your JSON:API endpoints can page through large datasets efficiently, avoiding offset limits and keeping results stable as records change.
page[cursor]/page[size] parameters, and spec-shaped links/meta over Laravel's native cursorPaginate(). With zero dependents and a single maintainer, "buy" realistically means adopting a few hundred MIT-licensed lines — vendor or fork them — rather than consuming a supported dependency. That reframes the decision as "do we want to own this source," which is answerable.OFFSET's linear cost, which can defer read-replica or index spend on deep list views — but only if a composite index matching the exact sort tuple exists. Approval should bundle that index as a prerequisite, not a follow-up, otherwise the change is a net slowdown.laravel-json-api and has no value outside that stack. It cannot inform "should we do JSON:API"; it only answers "we are on JSON:API, how do we paginate it." Framing it that way in roadmap discussions prevents it from being mistaken for general pagination investment.total/last, and how quickly the change can be reversed.composer.json.Consider it when:
laravel-json-api, and a client or the spec requires cursor pagination.OFFSET cost or result instability has been measured — duplicate or skipped rows in logs, slow deep pages — not merely assumed.created_at, id) can be mandated per endpoint, with a matching composite index signed off before shipping.400 error mapping against the pinned parent version.Look elsewhere when:
laravel-json-api. Call cursorPaginate() directly; there is no integration surface here. Same answer for API Resources, Fractal, spatie/laravel-query-builder, GraphQL, gRPC, and plain REST.For executives. This is a small, MIT-licensed add-on that lets our API serve long, continuously updating lists — feeds, activity logs, transaction history — without the duplicate-and-skip bugs and database cost of page-number pagination. It is cheap to evaluate (about a one-day spike) and cheap to own if we vendor it. The caveat is material and should be stated up front: effectively no community adoption and a single maintainer, so we treat it as source code we adopt, not a vendor product we depend on. Recommended posture: pilot on one endpoint behind a flag, fund a small amount of engineering time to own the code, and keep it off any critical path that lacks that ownership plan. It is also only relevant if we have already committed to JSON:API — if we have not, this is not the lever.
For engineering. It plugs into laravel-json-api as a pagination implementation, wrapping Laravel's native cursor paginator and emitting spec-shaped cursor links with page[cursor] and page[size]. The integration surface is narrow — a pagination class plus per-resource registration — so a spike should land under a day, including verifying behavior under concurrent inserts. Three things we must own in application code because the package cannot: a deterministic unique sort tuple (created_at, id) on every paginated endpoint, rejection or restart when the requested sort differs from the sort embedded in the cursor, and clean JSON:API 400 responses for malformed or stale cursors instead of 500s. Verify explicitly whether cursors are tamper-evident — base64-encoded sort values can be forged to probe outside an authorized filter set, which is an authorization concern, not a polish item. Confirm too whether relationship endpoints and nested filters are covered, and that omitting total/last is deliberate and documented, since front-end teams will assume they exist. Risks are provenance rather than code quality: Page contract drift on parent upgrades, no external CI signal to lean on, and edge cases (empty pages, cursor expiry, relation-heavy includes, NULL semantics, MySQL/PostgreSQL/SQLite collation differences) that become ours to find. Mitigation is straightforward: vendor or fork under an internal namespace, add characterization tests for link generation and stability under writes, keep the abstraction at the resource layer so clients are unaffected by a swap to in-house code, and run a CI job against the parent's next minor for early drift warning. If we are not already committed to JSON:API, do not adopt this — call cursorPaginate() directly.
How can I help you explore Laravel packages today?