How to Add Pagination to an Astro Blog
Split a long blog list into pages of ten, with Newer and Older links. Astro's paginate() does the math. You write one file, and Astro builds every page.
Tested on Astro 7.4

In this guide
Pagination splits a long list into pages, like page 1, page 2 and page 3. Astro has a helper for it called paginate(). You give it your posts and a page size. It builds every page and works out the Newer and Older links for you. One file does it all.
Step 1: Remove the old blog list
If you followed our blog guide, you have src/pages/blog/index.astro. That’s the page that lists every post. Delete it. The new file in step 2 takes its place.
This step matters. If you keep the old file, it wins, and your page 1 never shows.
Step 2: Make the paginated list
In src/pages/blog/, create a file called [...page].astro. Yes, with the square brackets and three dots:
---
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';
export async function getStaticPaths({ paginate }) {
const posts = (await getCollection('posts')).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
);
return paginate(posts, { pageSize: 10 });
}
const { page } = Astro.props;
---
<Layout title="Blog">
<h1>Blog</h1>
<ul>
{page.data.map((post) => (
<li><a href={`/blog/${post.id}/`}>{post.data.title}</a></li>
))}
</ul>
<nav>
{page.url.prev && <a href={page.url.prev}>← Newer posts</a>}
<span>Page {page.currentPage} of {page.lastPage}</span>
{page.url.next && <a href={page.url.next}>Older posts →</a>}
</nav>
</Layout>
Step 3: See how it works
The file name. The three dots in [...page] mean page 1 lives at /blog/ itself. Then come /blog/2, /blog/3, and so on. If you named it [page].astro instead, page 1 would be at /blog/1.
getStaticPaths runs once, when Astro builds your site. It gets every post and sorts them, newest first. Then paginate() cuts the list into pages of 10. Change pageSize to whatever you like.
The page box. Each page gets a page object with everything it needs:
page.datais this page’s posts. Only 10, not all of them.page.currentPageis this page’s number.page.lastPageis how many pages there are.page.url.prevandpage.url.nextare the links to the pages on each side.
The links. Page 1 has no newer page, so page.url.prev is empty and that link is skipped. The last page has no older page, so the Older link is skipped there. The && does that. It means “only show this if there’s a link.”
Your post pages keep working. A post at /blog/hello-world/ still uses your [id].astro file. Astro checks for a named page like that first.
Step 4: Build and check
To see more than one page with only a few posts, set pageSize: 2 for now. Then build:
npm run build
$ npm run build
19:30:17 ├─ /blog/index.html (+1ms)
19:30:17 ├─ /blog/2/index.html (+1ms)
19:30:17 ├─ /blog/3/index.html (+1ms)
19:30:17 [build] Complete!That’s a trimmed copy of our build with five posts. Five posts at two per page made three pages. Page 1 showed “Page 1 of 3” and an Older link only. Page 2 had both links. Page 3 had one post and a Newer link only.
Set pageSize back to 10 when you’re done.
We ran this on a fresh Astro 7.4 project. We checked the build and the dev server. In both, /blog/2/ showed page 2 and /blog/hello-world/ still showed the post.
Building with Claude? Paste this guide into Claude Code and ask it to do it for you.
Make it better
- Style the links. Put
display: flexandjustify-content: space-betweenon the<nav>to push the links to each side. - Show page numbers.
page.url.firstandpage.url.lastlink to the first and last pages, for long blogs. - Paginate a tag page too. The same
paginate()works inside a tag page. Combine it with our tags guide.
Where to go next
- How to add tags and categories to an Astro blog, so readers can browse by topic.
- How to add an RSS feed to Astro, so readers never miss a post.
- How to add a sitemap to Astro, so search engines find every page.
Frequently asked questions
What does paginate() do in Astro?
It takes your full list of posts and cuts it into pages of a size you pick. It makes one page for each piece and gives each page its posts plus links to the next and previous pages.
Why is my old blog page still showing instead of page one?
You still have src/pages/blog/index.astro. It wins over the new file. Delete it, and the new file builds the /blog/ page.
How many posts should go on each page?
Ten is a good start. Change pageSize to any number you like. Fewer posts per page means more pages.
Stuck on a step?
Check the common errors guide, look up a word in the glossary, or ask the friendly people in the official Astro and EmDash Discords. How to ask so people can help.