True O(1) Performance
Eliminates SQL OFFSET execution degradation on deep datasets by establishing stable indexed boundaries using composite keys.
Database-agnostic, zero-degradation pagination with cryptographic cursors for Drizzle ORM on Node.js and Bun.
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
import { createKeysetConfig, paginateKeyset, CryptoCursorProtector } from 'keysetengine-drizzle';
// 1. Define your Drizzle table
export const orders = sqliteTable('orders', {
id: integer('id').primaryKey(),
customerName: text('customer_name').notNull(),
orderNumber: text('order_number').notNull(),
createdAt: text('created_at').notNull(),
amount: integer('amount').notNull(),
});
// 2. Configure keyset boundary & search properties
export const orderKeyset = createKeysetConfig(orders, {
sortBy: orders.createdAt,
sortDirection: 'desc', // Default is 'asc'
tieBreaker: orders.id, // Must be unique and non-nullable
searchIn: [orders.customerName, orders.orderNumber],
entityPurpose: 'orders',
});
// 3. Paginate in your HTTP route handler (Hono, Express, Elysia, Fastify, Next.js)
const protector = new CryptoCursorProtector(process.env.CURSOR_SECRET!);
export async function getOrders(req) {
const page = await paginateKeyset(
db.select().from(orders).$dynamic(),
orderKeyset,
req.query, // { cursor, direction, limit, search }
{ protector }
);
return {
items: page.items,
startCursor: page.startCursor,
endCursor: page.endCursor,
hasNextPage: page.hasNextPage,
hasPreviousPage: page.hasPreviousPage,
};
}High Throughput at Deep Offsets
Unlike standard SQL OFFSET 100000 LIMIT 20 which forces your database engine to scan and discard 100,000 index entries, KeysetEngine translates queries directly into composite index seeks:
WHERE ("created_at" < $1) OR ("created_at" = $1 AND "id" < $2)
ORDER BY "created_at" DESC, "id" DESC
LIMIT 21Execution time remains consistently under 1 millisecond, regardless of table size or page depth.