Querying

Pagination

Use paginate() for offset pages and cursor() for cursor navigation.

paginate() is the offset helper. cursor() is the cursor helper. Both return { data, pagination }, but the metadata is specific to the strategy.

Offset pagination

Use limit with skip (or take) when the consumer needs totals and page numbers:

const page = await client.users.paginate({
	limit: 20,
	skip: 40,
	orderBy: [{ id: 'asc' }],
	where: { active: true },
});

page.data; // User[]
page.pagination.type; // "offset"
page.pagination.page;
page.pagination.perPage;
page.pagination.total;
page.pagination.pageCount;
page.pagination.hasNext;
page.pagination.hasPrevious;

Cursor pagination

Use cursor() for feed-style navigation:

const first = await client.users.cursor({
	limit: 2,
	orderBy: [{ id: 'asc' }],
});

const second = await client.users.cursor({
	limit: 2,
	orderBy: [{ id: 'asc' }],
	after: first.pagination.nextCursor as { id: number },
});

Pass before to move backwards. cursor() accepts before or after, never both.

const previous = await client.users.cursor({
	limit: 2,
	orderBy: [{ id: 'asc' }],
	before: { id: 4 },
});

Cursor pagination needs a stable order

Always pass a deterministic orderBy (typically including a unique column like the primary key) when paginating by cursor, or pages can overlap or skip rows.

Pagination with projection

Both helpers accept the same select / include as a normal read:

const page = await client.posts.paginate({
	limit: 10,
	orderBy: [{ id: 'desc' }],
	include: { author: true },
});

const feed = await client.posts.cursor({
	limit: 10,
	orderBy: [{ id: 'desc' }],
	include: { author: true },
});

Choosing offset vs cursor

StrategyGood forTrade-off
Offsetadmin tables, reporting, simple listseasy to reason about; weaker on very large, changing datasets
Cursorfeeds, timelines, large mutable datasetsneeds stable ordering and cursor discipline

On this page