VOOZH about

URL: https://blog.logrocket.com/pagination-in-graphql-with-prisma-the-right-way/

⇱ Pagination in GraphQL with Prisma the right way - LogRocket Blog


2020-01-16
652
#graphql
Gbolahan Olagunju
12444
👁 Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

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.

👁 GraphQL

It 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.

Using first or last with skip

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.

  • If we visit the public API, we’ll see the doc section.
  • Clicking the doc section, we’ll see the query, mutation, and subscription.
  • Then we’ll click on the query type to see all the queries that are available to us.

For the purposes of this article, we will be using the allStarships query.


🚀 Sign up for The Replay newsletter

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.

Over 200k developers use LogRocket to create better digital experiences

👁 Image
Learn more →

 {
 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.

Using before or after with skip

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.

👁 load more posts

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.

Conclusion

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.

Monitor failed and slow GraphQL requests in production

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 Banner
👁 LogRocket Dashboard Free Trial Banner

LogRocket 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.

👁 Image
👁 Image
👁 Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

How to build a virtual engineering team with Gemini CLI subagents

Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.

👁 Image
Emmanuel John
Jun 18, 2026 ⋅ 10 min read

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

👁 Image
Emmanuel John
Jun 17, 2026 ⋅ 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

👁 Image
Chizaram Ken
Jun 16, 2026 ⋅ 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.

👁 Image
Ikeh Akinyemi
Jun 12, 2026 ⋅ 6 min read
View all posts

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