amrnn/laravel-cursor-paginator
Cursor-based pagination for Laravel. amrnn/laravel-cursor-paginator provides a paginator that uses cursors instead of offsets, useful for APIs and large datasets where stable, efficient paging matters. A small, focused package for Eloquent queries.
Architecture fit. The package delivers cursor (keyset) pagination for Laravel's query builder/Eloquent: instead of LIMIT/OFFSET, it encodes the last row's sort position into an opaque cursor and issues WHERE (sort_key) > (last_value) ORDER BY sort_key LIMIT n. That is the correct pattern for deep pagination over large tables — it is O(1) in offset depth, stable under concurrent inserts, and avoids the OFFSET 500000 table scan. Architecturally it's a thin, well-understood layer, not an invasive one.
The decisive issue is redundancy. Laravel 8 shipped first-party cursorPaginate() on the query builder and Eloquent, with an official CursorPaginator class, cursor/per_page request params, and next_cursor/prev_cursor in the JSON payload. This package predates that and now duplicates a framework primitive. Any adoption decision is really a "why not the built-in?" decision, and there is no strong answer for a modern Laravel app.
Integration feasibility. Mechanically trivial (Composer install, apply trait/scope, swap paginator call). Strategically weak: 19 stars means effectively no community, a single maintainer, no external code review, and a near-zero bug-fix surface. The repository is archived — frozen code, no security advisories, no PHP/Laravel compatibility updates.
Technical risk.
CursorPaginator/cursorPaginate overlapping the framework's own symbols can cause subtle resolution bugs or accidental dual code paths.Key questions.
composer.lock anywhere, and how many call sites use it?Recommendation: do not adopt. Treat this as a migration-off target, not an integration-on candidate. The 1.15 score and archived status are consistent with that.
Stack fit. Composer-installed Laravel package; only meaningfully additive on Laravel ≤7, which is end-of-life and a standing security liability. The real project in that scenario is the framework upgrade, not the pagination package.
Migration path (if already present):
composer.json/composer.lock and the codebase for the trait, service provider, and paginator class; count endpoints affected.cursorPaginate($perPage, ['*'], 'cursor', $cursor). Make ordering explicit (->orderBy('id') or ->orderBy('created_at')->orderBy('id')) — native requires at least one order column and will throw without it.{data, per_page, next_cursor, prev_cursor} and accept cursor/per_page params; update API docs and clients.config/app.php or package discovery cache.Compatibility checks. Confirm the sort keys are unique or tie-broken by a unique column; confirm no reliance on total counts or page-number navigation in the consuming UI; confirm the package's cursor encoding isn't persisted in caches, URLs, or client-side state that would break on format change.
Sequencing. Discovery → index/ordering hardening → shadow-run old and new responses on a sample endpoint and diff → cut over endpoint-by-endpoint behind a feature flag → delete the dependency. Do not attempt a big-bang swap across all endpoints; pagination regressions show up as missing or duplicated rows, which are hard to spot and easy to blame on the data layer.
Maintenance. If retained, cost is non-zero despite being "frozen": archived code still has to be proven compatible on every Laravel/PHP upgrade, and you own that proof. Removing it transfers maintenance to the framework vendor — a strict improvement in ownership economics.
Support. None available. No maintainer response, no issue triage, no CVE feed. Internal forks of 19-star packages typically degrade into untested vendor code that everyone is afraid to touch.
Scaling. The cursor pattern itself scales well — stable query cost regardless of depth, lower buffer-pool pressure than deep offsets, and better behavior under concurrent writes. The package delivers that benefit, but so does the built-in, so this is not a differentiator.
Failure modes to watch.
prev_cursor) cost and correctness are the usual weak spot in third-party implementations.total()/page-jump capability → UI regressions where the frontend assumed offsets.Ramp-up. Low for engineers — any Laravel developer understands the pattern in an hour. The real ramp-up cost sits with API consumers and frontend teams adapting from offset/page semantics to opaque cursors, and with the on-call team learning that cursor errors are client-contract issues, not infrastructure incidents. Budget the communication effort there, not in engineering.
How can I help you explore Laravel packages today?