Super Simple Server Side Pagination in Next.js
With the introduction of the App router and server components in Next.js 13, it's now super simple to create an indexable pagination system with the help of URL parameters.
For a demonstration of this functionality, simply see this very blog! If you go to the main blog listing, you'll see the first 12 posts, with a 'next' button that will take you to page 2 of the blog, showing the next 12 posts, etc. and so on.
So let's get to it!
Querying a range of posts
First of all, we need to query our database for our posts. My posts are stored in Sanity CMS so that's what I'll be using for this example, but the query should hopefully be fairly similar whatever database/CMS you're using.
In this query, instead of getting all posts, we need to specify the range of posts we want to fetch; for example, posts 1 to 10.
The following groq query would get the first 10 posts.
This is fine for our first page, but we need to make those values dynamic so we can get the correct range of posts for pages 2, 3 and so on. So we need to add two arguments to the function for start
and end
, and then use those values within the function in place of the static values.
Now we need to pass the appropriate start/end values through to this function for each page. So over to our blog listing page template...
Preparing the blog listing for pagination
Without pagination, we would simply import that getPosts()
function and then store the results in a variable.
Now, we need to pass through the appropriate $start
and $end
arguments to the function. We know that for the first page this would simply be:
To calculate these arguments based on the current page, first of all let's set up the variables we will need.
Using URL Parameters to get the current page number
Now we need that pageNum
variable to change based on the current page number. We will achieve this using URL query string parameters, which Next.js makes available to your page component.
It makes sense to call our parameter 'page', so our blog pages will take the following format:
- /blog
- /blog?page=2
- /blog?page=3
- etc.
We can get access to the value of this 'page' parameter using Next.js's searchParams
prop.
Here, we are checking if searchParams.page
has a value, ensuring this is a Number
type, and then applying this value to the pageNum
variable. And if the page
parameter isn't set on the URL, we must be on the main blog page, so the pageNum
variable is set to 1
.
The next step is to use the limit
and pageNum
variables to calculate the appropriate start and end values to send through to the getPosts
function.
Let's break down this calculation so we can understand what's happening here:
Page 1
Page 2
Page 3
And just like that our pagination is in place! The main blog listing should now display the first 10 posts, /blog?page=2 should show posts 11-20, and so on.
Adding Next and Previous Buttons
The final step is to add next and previous buttons, so the user can navigate between the blog pages. This is fairly straightforward, again using the current page number to output the appropriate href values.
To break down what's happening here, for the Previous button, we only want to display this when not on page 1. If we're on page 2, just output '/blog' as the href value. Otherwise, we can pass an object which takes a pathname
and query
value. The pathname is '/blog', and for the query, we set page to pageNum - 1
, so on page 3 for example it would link to /blog?page=2.
For the Next button, it's a similar story. Simply set the page parameter to pageNum + 1
this time, so on page 3 for example it would link to /blog?page=4.
And there we have it! Simple, server-side pagination with physical, shareable URLs.