Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for Postgres Difficulty: Intermediate ClaudeChatGPTCursor

Postgres Keyset (Cursor) Pagination Optimization Prompt

Convert a slow OFFSET/LIMIT pagination query into stable keyset (seek) pagination that stays fast on deep pages — with a matching index and a correct tuple-comparison predicate, not a broken one-column WHERE.

Target user
Backend engineers whose list endpoints slow down on high page numbers
Difficulty
Intermediate
Tools
Claude, ChatGPT, Cursor

The prompt

You are a senior PostgreSQL engineer who has fixed dozens of paginated endpoints that
fall over on deep pages. You reason from the index and the ORDER BY, and you get the
tuple-comparison semantics exactly right, because an off-by-one here silently skips or
repeats rows.

I will paste:
- The current query (with ORDER BY, OFFSET, LIMIT): [CURRENT QUERY]
- The plan on a DEEP page from `EXPLAIN (ANALYZE, BUFFERS)`: [EXPLAIN OUTPUT]
- The table's existing indexes: [INDEXES]
- The sort key(s) and whether the last one is unique (e.g. created_at + id): [SORT KEYS]
- Any filters applied alongside pagination (tenant_id, status): [FILTERS]

Work through this in order:

1. **Explain the OFFSET cost** from the plan: OFFSET N still reads and discards N rows,
   so page cost grows linearly with depth. Point at the rows read vs rows returned.

2. **Design the keyset predicate correctly.** For a compound sort like
   `ORDER BY created_at DESC, id DESC`, the seek predicate must be a row comparison:
   `WHERE (created_at, id) < ($last_created_at, $last_id)`. Explain why splitting it into
   `created_at < x OR (created_at = x AND id < y)` is required only when directions differ,
   and why a naive single-column `created_at < x` skips or duplicates rows at boundaries.
   Always require a unique tiebreaker (the primary key) as the final sort key.

3. **Match the index to the ORDER BY** exactly, including column order, direction, and
   any leading equality filter (tenant_id first). Give the `CREATE INDEX CONCURRENTLY`
   DDL and confirm the composite key supports the seek without a sort node.

4. **Handle the API contract**: what cursor to return to the client (the last row's sort
   key values, encoded), how the first page differs (no predicate), and how to page
   backward.

5. **Give a verification step**: the exact seek query with example cursor values, the
   EXPLAIN that should now show an Index Scan with no OFFSET and constant rows read
   regardless of page depth, and a correctness check that no row is skipped or repeated
   across a boundary.

Output: (a) the rewritten seek query; (b) the index DDL; (c) the cursor format; (d) the
before/after EXPLAIN expectation; (e) one correctness pitfall to test.

Guardrails: keyset pagination cannot jump to an arbitrary page number — confirm the UI
only needs next/prev before recommending it. Require a unique final sort key or rows on a
tie boundary will be lost. Build indexes CONCURRENTLY and validate on a replica.

Run this prompt with AI

Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.

Why this prompt works

Deep-page pagination is a textbook performance cliff: OFFSET 100000 reads and throws away a hundred thousand rows before returning the page you want, so latency climbs with page number. The fix — keyset (seek) pagination — is well known, but the two ways it breaks are subtle: the tuple-comparison predicate is easy to get wrong, and forgetting a unique tiebreaker corrupts results at page boundaries. This prompt centers both, forcing the correct row-value comparison and a unique final sort key.

It also refuses to hand-wave the index. The seek only stays O(1) per page if a composite index matches the ORDER BY column-for-column, direction-for-direction, with any equality filter leading. By pairing the rewrite with exact DDL, a cursor-format contract, and a boundary correctness check, the prompt delivers a change that is both fast and provably lossless — and the guardrail about arbitrary page jumps stops teams from adopting keyset where the UI genuinely needs numbered pages.

Related prompts

More Postgres prompts & error guides

Browse every Postgres prompt and troubleshooting guide in one place.

Free download · 368-page PDF

Reading prompts? Get all 500 in one free PDF

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.