![]() |
VOOZH | about |
When working with a database that has millions of records, it’s very useful to adopt pagination since it helps us retrieve a subset of the data that we otherwise wouldn’t be able to access without querying every record on the table.
👁 GraphQLIt can very expensive to retrieve this information from our database and it can have a huge impact on performance. It can also be expensive to render on the client side.
As of this writing, the default amount of records retrieved by Prisma on a table is 1,000 records — that is, if a subset of the record isn’t requested.
When querying a list of records, we can fetch certain parts (i.e. pages) of that list by supplying pagination arguments.
There are 5 major arguments we can use for pagination in Prisma: first, last, after, before, and skip.
In this article, we’ll be looking at various ways we can combine these arguments to effectively paginate our data.
We’ll also be using this public API for sample demonstrations.
Imagine an app that has pagination implemented with buttons as indicated below and has a page size of 10 items.
To get this to work, we would need to rewrite our typedef definition to accept arguments and also implement it in the resolver function for that query.
We won’t be doing that, seeing as how we are using an already-built public API. Looking at the documentation for this shows that the query has been defined to accept those arguments.
Okay, let’s get our feet wet.
For the purposes of this article, we will be using the allStarships query.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
{
allStarships(first: 10) {
id
name
length
manufacturer
}
}
When we ran this code, a total of 10 records were returned. However, this isn’t complete for pagination because the same set of 10 records will be returned every time.
To ensure it works properly, we need to introduce another argument called skip.
Here’s how:
{
allStarships(first: 10, skip: 10) {
id
name
length
manufacturer
}
}
This gives us the second page, or the next 10 records. This can be done dynamically by sending the page number from the buttons multiplied by our page size.
We can get the first, second, and third page like this:
//first page // number to skip pageNumber = 1 number = 10 * (1 - 1); // 0 ... allStarships(first: 10, skip: 0) //second page //number = 10 * (2 - 1); // 10 allStarships(first: 10, skip: 10) // third page //number = 10 * (2 - 1); // 10 allStarships(first: 10, skip: 20) 👁 Pagination
We could also use the last argument, but we would be querying the table (collection if mongoDB was the database of choice) from the last record entered rather than the above, which queries from the top of the table.
Imagine we have the navigation of a page implemented such that when you get to the bottom of the page, you can use the last id to fetch more records after it.
In our example, we can decide to fetch 10 more records.
Here’s how it’ll look in code:
{
allStarships(first: 10, skip: 10) {
id
name
length
manufacturer
}
}
This gets us 10 records after the specified id . We can also use last with before to get records before the specified id.
Note: We can’t combine the use of first with before, or last with after.
If we do that in a query, the first or last is what will be applied (at either the end or the beginning of the list, depending on which is being used) while the before or after argument is simply ignored.
It’s important to apply pagination when querying records from our database because it helps to optimize the performance of our servers. It also helps to curb expensive renders at the client level.
While GraphQL has some features for debugging requests and responses, making sure GraphQL reliably serves resources to your production app is where things get tougher. If you’re interested in ensuring network requests to the backend or third party services are successful, try LogRocket.
👁 LogRocket Dashboard Free Trial BannerLogRocket lets you replay user sessions, eliminating guesswork around why bugs happen by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks.
LogRocket's Galileo AI watches sessions for you, instantly aggregating and reporting on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.
Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.
Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.
Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.
TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now