Database Integration with PrismaLesson 4.4
How to implement pagination with Prisma and Next.js
offset pagination, cursor-based pagination, take and skip, cursor and after, total count, page params, Prisma transaction for count
Offset Pagination
Offset pagination uses take (limit) and skip (offset). Read the page number from the URL's search params:
// app/blog/page.tsx
const PAGE_SIZE = 10
export default async function BlogPage({
searchParams,
}: {
searchParams: { page?: string }
}) {
const page = Number(searchParams.page ?? 1)
const skip = (page - 1) * PAGE_SIZE
const [posts, total] = await prisma.$transaction([
prisma.post.findMany({
where: { published: true },
take: PAGE_SIZE,
skip,
orderBy: { createdAt: 'desc' },
}),
prisma.post.count({ where: { published: true } }),
])
const totalPages = Math.ceil(total / PAGE_SIZE)
return (
<div>
{posts.map(p => <PostCard key={p.id} post={p} />)}
<Pagination currentPage={page} totalPages={totalPages} />
</div>
)
}Cursor-Based Pagination
// Faster for large datasets, but no random page access
const posts = await prisma.post.findMany({
take: PAGE_SIZE,
skip: cursor ? 1 : 0, // Skip the cursor record itself
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
})
const nextCursor = posts[posts.length - 1]?.idOffset pagination is simple but slow on large tables. Cursor-based pagination is fast regardless of dataset size but can't jump to arbitrary pages. Use offset for admin lists, cursor for infinite scroll feeds.
