Cursor vs offset pagination: quando usar cada
Descubra, de forma prática, as diferenças e limitações entre cursor-based pagination e offset-based pagination e saiba quando escolher cada abordagem.
Por que isso é importante
Cursor based pagination vs offset: quando usar cada uma? Offset para jump-to-page (admin). Cursor/keyset para infinite scroll e feeds grandes — evita deep OFFSET e shifting window. Cursor opaco + LIMIT+1 para hasMore.
Leitura relacionada: paginação cursor na prática · como criar API REST com Node.js · guia de normalização de banco · SQL para quem veio do NoSQL · tipos de filas no RabbitMQ.
O que é Offset-Based Pagination?
Offset-based pagination usa LIMIT + OFFSET: página N = pular (N−1)×pageSize registros. Simples e permite jump-to-page — mas em tabelas grandes o deep OFFSET fica lento e inserts/deletes deslocam a janela.
Atenção
O offset no banco de dados exige leitura sequencial dos registros, o que pode causar
lentidão em grandes volumes de dados.
O que é Cursor-Based Pagination?
Cursor-based (keyset) pagination usa um marcador do último item (ex.: created_at+id). A próxima página pede “depois deste cursor” — estável em feeds e infinite scroll, sem pular OFFSET profundo.
Atenção
No cursor-based, não existe o conceito nativo de página específica. O usuário só
consegue avançar ou retroceder sequencialmente.
Quando o Offset não representa a ordem de exibição?
OFFSET na ordem do ID interno só funciona se a UI ordenar pelo mesmo critério. Se a lista ordena por posição, published_at ou score, o “pulo” de registros não bate com a página que o usuário vê.
Atenção
Assumir que o ID sempre é a ordem exata pode comprometer a lógica de paginação —
principalmente quando registros podem ser reordenados, editados ou removidos.
Como funciona a navegação para páginas específicas no Offset?
Na estratégia offset, a possibilidade de navegar diretamente para qualquer página é uma
de suas maiores vantagens. Exemplo: se há 20 posts por página e você quer acessar a
página 21, basta pular os 400 primeiros (20 x 20) e retornar do item 401 ao 420.
Limitações da Cursor-Based Pagination
O cursor-based pagination não permite acesso direto a uma página arbitrária — sempre é
necessário passar pelo(s) cursor(es) anterior(es). Isso pode dificultar para quem
precisa pular para uma página específica, mas aumenta a eficiência para buscas
sequenciais e scroll infinito.
Quando usar Cursor-Based Pagination?
Use cursor/keyset quando o feed é grande ou infinite scroll: próxima página = “depois deste cursor”, sem deep OFFSET nem janela que desloca com inserts.
- Passo 1: Avalie se o volume de dados é alto e o scroll infinito
é desejado para UX moderna. - Passo 2: Implemente quando performance na navegação sequencial
for crítica e não há necessidade de pular direto para uma página distante.
Atenção
Cursor-based não permite “pular” para a página 20 instantaneamente; exige navegação
por etapas.
Quando usar Offset-Based Pagination?
Use offset quando a UI precisa de jump-to-page N (tabela admin, páginas numeradas) e o dataset cabe sem deep OFFSET caro.
- Passo 1: Escolha quando o usuário precisa de navegação direta
por páginas (como em tabelas administrativas). - Passo 2: Prefira quando o volume de dados não for extremo ou
ordenação exata por campos for essencial.
Comparativo prático: offset vs cursor (e keyset)
Resumo: offset = navegar por número de página; cursor/keyset = estabilidade e escala em feeds. Keyset é o cursor “de verdade” no SQL; cursor opaco só empacota o keyset.
Offset-Based Pagination
Paginação tradicional por saltos (offsets)
+ Prós
- • Permite navegar direto para qualquer página
- • Controle total de páginas e ordenações variadas
− Contras
- • Escala mal em grandes tabelas
- • Pode exibir resultados inconsistentes se dados mudarem durante a navegação
Cursor-Based Pagination
Paginação por marcadores (cursored navigation)
+ Prós
- • Alta performance em tabelas extensas
- • Ideal para scroll infinito e navegação sequencial
− Contras
- • Não permite saltar para uma página arbitrária
- • A navegação é feita por etapas sequenciais apenas
Implementação Node + Postgres: cursor opaco
Padrão colável (Node + Postgres): cursor opaco = base64url de { createdAt, id }. Índice composto (created_at, id). Query keyset com tuple comparison e LIMIT+1 para hasMore:
WHERE (created_at, id) < ($1, $2) ORDER BY created_at DESC, id DESC LIMIT $3 — decode do cursor alimenta $1/$2; se vierem N+1 rows, pop a extra e encode nextCursor. Envelope: { items, nextCursor, hasMore }. Mesmo modelo mental do Convex .paginate (cursor + página) — sem inventar benchmarks de latency.
Tie-breaker
Nunca paginar só por created_at se houver empates — o id desempata e evita duplicar/pular linhas.
Ferramentas: Relay, libs e Convex.paginate
Prisma
ORM moderno para Node.js com suporte a cursor pagination
TypeORM
ORM TypeScript compatível com estratégias offset e cursor
Apollo GraphQL
Suporte pronto a paginação cursor-based através de connections
Sequelize
ORM popular para Node.js com suporte tradicional a offset
Principais erros ao escolher paginação
- Erro comum: Assumir que a ordenação pelo ID sempre é a
desejada. - Erro comum: Usar offset em bancos com milhões de registros sem
índices otimizados. - Erro comum: Implementar cursor quando navegação por página fixa
é indispensável para o negócio.
Dica
Sempre alinhe o tipo de paginação com as expectativas de uso definidas junto ao time
de produto.
Árvore de decisão: qual paginação escolher
Analise cuidadosamente o volume de dados envolvido, os requisitos de navegação do seu
sistema e o padrão de acesso mais utilizado pelos usuários antes de escolher entre
offset ou cursor. A escolha certa pode representar a diferença entre uma experiência
fluida ou frustrante.
Admin jump-to-page vs infinite scroll
Tabela de decisão rápida:
Offset (admin)
Painel com “ir à página N” e ordenação arbitrária.
+ Prós
- • Jump-to-page familiar
- • Ordenação livre no grid
− Contras
- • Deep OFFSET fica caro em tabelas grandes
- • Aceite o custo ou filtre por data/id antes
Cursor / keyset (feed)
Timeline, infinite scroll e sync mobile.
+ Prós
- • Feed estável sob inserts
- • Bom para mobile e sync
− Contras
- • Não finge número de página estável
- • Precisa índice composto (created_at, id)
API híbrida
Offset só em /admin; cursor em /feed.
+ Prós
- • Contrato certo por superfície
- • Documenta os dois modos
− Contras
- • Não misture os contratos no mesmo endpoint sem documentar
Se o admin precisar de jump e o volume explodir, filtre por data/id antes do OFFSET ou ofereça busca. Inclua índice composto (created_at, id) e truque LIMIT+1 para hasNext.
Checklist de Implementação
Checklist de Implementação
- Avaliou o formato de navegação esperado (página específica vs scroll sequencial)
- Revisou limitações de cada modelo de paginação
- Testou a performance em grandes volumes
- Considerou ordenação customizada além do ID
- Implementou fallback para mudanças de dados dinâmicos
Fontes
Revisão em agosto de 2026. Offset vs cursor/keyset é trade-off de produto (jump-to-page vs feed estável) — valide no seu banco e ORM. Exemplos didáticos, não benchmark universal de latência.
Convex — Pagination. PostgreSQL — LIMIT/OFFSET. Use The Index, Luke — No OFFSET.
Perguntas frequentes
Qual a diferença entre cursor-based pagination e offset?
Offset usa LIMIT/OFFSET (página N); cursor/keyset busca a partir de um ponto estável (id + created_at). Cursor escala melhor em feeds grandes; offset é simples e ok em listas pequenas.
Quando usar offset pagination?
Use offset em admin, tabelas pequenas ou quando o usuário precisa pular para a página N. Evite em feeds com inserts/deletes frequentes ou páginas muito profundas.
Cursor pagination permite pular para a página N?
Em geral não de forma estável: o cursor marca posição na ordenação, não um número de página. Para infinite scroll e APIs grandes, isso é o trade-off correto.
Como fazer cursor pagination no PostgreSQL?
Ordene com tie-breaker (ex.: created_at, id), filtre WHERE (created_at, id) < última tupla, LIMIT+1 para has_next e encode um cursor opaco. No Convex, o mental model é o mesmo com .paginate.
Continue explorando
Perguntas frequentes
Qual a diferença entre cursor-based pagination e offset?
Offset usa LIMIT/OFFSET (página N); cursor/keyset busca a partir de um ponto estável (id + created_at). Cursor escala melhor em feeds grandes; offset é simples e ok em listas pequenas.
Quando usar offset pagination?
Use offset em admin, tabelas pequenas ou quando o usuário precisa pular para a página N. Evite em feeds com inserts/deletes frequentes ou páginas muito profundas.
Cursor pagination permite pular para a página N?
Em geral não de forma estável: o cursor marca posição na ordenação, não um número de página. Para infinite scroll e APIs grandes, isso é o trade-off correto.
Como fazer cursor pagination no PostgreSQL?
Ordene com tie-breaker (ex.: created_at, id), filtre WHERE (created_at, id) < última tupla, LIMIT+1 para has_next e encode um cursor opaco. No Convex, o mental model é o mesmo com .paginate.
O que é Offset-Based Pagination?
Offset-based pagination usa LIMIT + OFFSET: página N = pular (N−1)×pageSize registros. Simples e permite jump-to-page — mas em tabelas grandes o deep OFFSET fica lento e inserts/deletes deslocam a janela.
O que é Cursor-Based Pagination?
Cursor-based (keyset) pagination usa um marcador do último item (ex.: created_at+id). A próxima página pede “depois deste cursor” — estável em feeds e infinite scroll, sem pular OFFSET profundo.
Quando o Offset não representa a ordem de exibição?
OFFSET na ordem do ID interno só funciona se a UI ordenar pelo mesmo critério. Se a lista ordena por posição, published_at ou score, o “pulo” de registros não bate com a página que o usuário vê.
Como funciona a navegação para páginas específicas no Offset?
Na estratégia offset, a possibilidade de navegar diretamente para qualquer página é uma de suas maiores vantagens. Exemplo: se há 20 posts por página e você quer acessar a página 21, basta pular os 400 primeiros (20 x 20) e retornar do item 401 ao 420.
Quando usar Cursor-Based Pagination?
Use cursor/keyset quando o feed é grande ou infinite scroll: próxima página = “depois deste cursor”, sem deep OFFSET nem janela que desloca com inserts.
Quando usar Offset-Based Pagination?
Use offset quando a UI precisa de jump-to-page N (tabela admin, páginas numeradas) e o dataset cabe sem deep OFFSET caro.