Using Sanity to generate a static blog with pagination

1 replies
Last updated: Apr 2, 2020
Is there a way to use Sanity to generate a static blog (Next or Gatsby) with static pagination? 🤔
AI Update

Absolutely! You can use Sanity to generate a static blog with static pagination using either Next.js or Gatsby. Here's how:

Static Pagination with Next.js

For Next.js, you'll use generateStaticParams (App Router) or getStaticPaths (Pages Router) to pre-generate paginated pages at build time. The key is to use efficient GROQ pagination techniques to fetch your content.

Example with Next.js App Router:

// app/blog/[page]/page.tsx
import { sanityFetch } from '@/sanity/lib/client'
import { defineQuery } from 'next-sanity'

const POSTS_PER_PAGE = 10

// Generate static pages for each pagination page
export async function generateStaticParams() {
  const totalPosts = await sanityFetch({
    query: defineQuery(`count(*[_type == "post"])`),
  })
  
  const totalPages = Math.ceil(totalPosts / POSTS_PER_PAGE)
  
  return Array.from({ length: totalPages }, (_, i) => ({
    page: (i + 1).toString(),
  }))
}

// Fetch posts for each page
export default async function BlogPage({ params }: { params: { page: string } }) {
  const pageNum = parseInt(params.page)
  const start = (pageNum - 1) * POSTS_PER_PAGE
  
  const posts = await sanityFetch({
    query: defineQuery(`
      *[_type == "post"] 
      | order(publishedAt desc) 
      [${start}...${start + POSTS_PER_PAGE}] {
        _id,
        title,
        slug,
        publishedAt,
        excerpt
      }
    `),
  })
  
  return (
    <div>
      {posts.map(post => (
        <article key={post._id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

Better Performance: Filter-Based Pagination

For better performance, especially with large datasets, use filter-based pagination instead of array slicing. This approach is much more efficient:

export async function generateStaticParams() {
  const POSTS_PER_PAGE = 10
  let lastId = ''
  const pages = []
  let pageNum = 1
  
  while (true) {
    const posts = await sanityFetch({
      query: defineQuery(`
        *[_type == "post" && _id > $lastId] 
        | order(_id) 
        [0...${POSTS_PER_PAGE}] {
          _id
        }
      `),
      params: { lastId },
    })
    
    if (posts.length === 0) break
    
    pages.push({ page: pageNum.toString() })
    lastId = posts[posts.length - 1]._id
    pageNum++
  }
  
  return pages
}

Gatsby Static Pagination

For Gatsby, you'll use the createPages API in gatsby-node.js:

const path = require('path')

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const POSTS_PER_PAGE = 10
  
  // Query total post count from Sanity
  const result = await graphql(`
    {
      allSanityPost(sort: { publishedAt: DESC }) {
        totalCount
        nodes {
          _id
          slug {
            current
          }
        }
      }
    }
  `)
  
  const posts = result.data.allSanityPost.nodes
  const totalPages = Math.ceil(result.data.allSanityPost.totalCount / POSTS_PER_PAGE)
  
  // Create paginated blog list pages
  Array.from({ length: totalPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/blog` : `/blog/${i + 1}`,
      component: path.resolve('./src/templates/blog-list.js'),
      context: {
        limit: POSTS_PER_PAGE,
        skip: i * POSTS_PER_PAGE,
        currentPage: i + 1,
        totalPages,
      },
    })
  })
}

Key Considerations

  1. Performance: For datasets with thousands of posts, use filter-based pagination with _id sorting instead of array slicing for much better build performance

  2. Incremental Static Regeneration (ISR): With Next.js, you can use ISR to update pages after build time without full rebuilds

  3. sanityFetch: Use this helper in Next.js for automatic caching and revalidation configuration

  4. Build Time: Consider the total number of pages you're generating - too many can slow down builds significantly

Both approaches work great with Sanity! Next.js with App Router gives you more modern features and flexibility, while Gatsby remains a solid choice for traditional static sites.

With Gatsby that’s pretty easy. You can get a blog up and running in minutes with Sanity’s blog starter:
https://www.sanity.io/create?template=sanity-io%2Fsanity-template-gatsby-blog
Then follow this guide to add the pagination:

https://www.gatsbyjs.org/docs/adding-pagination/

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?