Fix: Page Number Param Not Found in Astro

Error message:
Page number param not found.
Routing & Pages 2025-01-25

What Causes This Error?

This error occurs when you use the paginate() function but your route filename doesn’t include a [page] or [...page] parameter. Pagination requires this parameter to generate URLs like /blog/1, /blog/2, etc.

The Problem

---
// src/pages/blog.astro ❌ No page parameter in filename
import { getCollection } from 'astro:content';

export async function getStaticPaths({ paginate }) {
  const posts = await getCollection('blog');
  return paginate(posts, { pageSize: 10 });
}
---

The Fix

Add Page Parameter to Filename

# Rename your file to include [page] or [...page]

# Option 1: Required page number
src/pages/blog/[page].astro       # /blog/1, /blog/2, etc.

# Option 2: Optional page number (recommended)
src/pages/blog/[...page].astro    # /blog, /blog/2, /blog/3, etc.
---
// src/pages/blog/[...page].astro ✅
import { getCollection } from 'astro:content';

export async function getStaticPaths({ paginate }) {
  const posts = await getCollection('blog');
  return paginate(posts, { pageSize: 10 });
}

const { page } = Astro.props;
---

<h1>Blog Posts (Page {page.currentPage})</h1>

{page.data.map((post) => (
  <article>
    <h2>{post.data.title}</h2>
  </article>
))}

<nav>
  {page.url.prev && <a href={page.url.prev}>Previous</a>}
  {page.url.next && <a href={page.url.next}>Next</a>}
</nav>

Common Scenarios

Basic Pagination

---
// src/pages/posts/[...page].astro
export async function getStaticPaths({ paginate }) {
  const posts = await getCollection('blog');

  // Sort by date
  posts.sort((a, b) =>
    new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
  );

  return paginate(posts, { pageSize: 12 });
}

const { page } = Astro.props;
---

<ul>
  {page.data.map((post) => (
    <li>
      <a href={`/posts/${post.slug}`}>{post.data.title}</a>
    </li>
  ))}
</ul>

<div>
  Page {page.currentPage} of {page.lastPage}
</div>

Pagination with Categories

---
// src/pages/category/[category]/[...page].astro
import { getCollection } from 'astro:content';

export async function getStaticPaths({ paginate }) {
  const posts = await getCollection('blog');
  const categories = [...new Set(posts.map((p) => p.data.category))];

  return categories.flatMap((category) => {
    const filtered = posts.filter((p) => p.data.category === category);
    return paginate(filtered, {
      params: { category },
      pageSize: 10,
    });
  });
}

const { page } = Astro.props;
const { category } = Astro.params;
---

<h1>{category} Posts</h1>

Pagination with Tags

---
// src/pages/tag/[tag]/[...page].astro
export async function getStaticPaths({ paginate }) {
  const posts = await getCollection('blog');
  const tags = [...new Set(posts.flatMap((p) => p.data.tags || []))];

  return tags.flatMap((tag) => {
    const filtered = posts.filter((p) => p.data.tags?.includes(tag));
    return paginate(filtered, {
      params: { tag },
      pageSize: 10,
    });
  });
}
---

Page vs …page

# [page].astro - Page number is REQUIRED
/blog/1  ✅
/blog/2  ✅
/blog    ❌ 404

# [...page].astro - Page number is OPTIONAL
/blog    ✅ (shows page 1)
/blog/2  ✅
/blog/3  ✅

Custom Page Size

---
export async function getStaticPaths({ paginate }) {
  const items = await fetchItems();

  return paginate(items, {
    pageSize: 20,  // Items per page
  });
}
---

Quick Checklist

  • Filename must include [page] or [...page]
  • Use [...page] for optional first page (recommended)
  • Access pagination via Astro.props.page
  • Use page.url.prev and page.url.next for navigation
  • Combine with other params using params option