Reduce initial data load for paginated blog posts in Sanity/Next.js

11 replies
Last updated: Jan 27, 2026
Hi all,
I'm getting the following:
Warning: data for page "/numeros" is 1.16 MB which exceeds the threshold of 128 kB, this amount of data can reduce performance.

I have a query that outputs 137 blog results in a grid. Only 6 are displayed at a time on first load, with a "load more" button displaying 6 additional articles on every click using
.slice()
.
Is there a better (more performant) way of going about this, such that I don't need to query all the data on page load?
AI Update

You're hitting a common performance issue with Next.js when loading too much data at once! The good news is there are several better approaches than fetching all 137 blog posts upfront and using client-side .slice().

Better Approaches

Instead of fetching all posts and slicing on the client, use GROQ's built-in pagination operators to fetch only what you need:

*[_type == "post"] | order(publishedAt desc) [0...6]

For subsequent loads, you can use offset-based pagination:

*[_type == "post"] | order(publishedAt desc) [6...12]  // next 6
*[_type == "post"] | order(publishedAt desc) [12...18] // next 6

Implement this with Next.js API routes or Server Actions (App Router) that accept a page or offset parameter, so each "load more" click fetches fresh data from Sanity rather than loading everything upfront.

2. Cursor-Based Pagination (More Robust)

For better performance and consistency (especially if content changes between loads), use cursor-based pagination with _id or _createdAt:

*[_type == "post" && _createdAt < $lastCreatedAt] 
  | order(_createdAt desc) [0...6]

Pass the last item's _createdAt value as $lastCreatedAt for the next batch. This prevents duplicate or skipped items if posts are added/removed between loads.

3. Use SWR or useSWRInfinite

If you're using client components, useSWRInfinite works great for "load more" patterns:

import useSWRInfinite from 'swr/infinite'

const getKey = (pageIndex, previousPageData) => {
  if (previousPageData && !previousPageData.length) return null
  return `/api/posts?page=${pageIndex}&limit=6`
}

const { data, size, setSize } = useSWRInfinite(getKey, fetcher)

Your /api/posts route would query Sanity with the appropriate GROQ pagination.

4. Move to getServerSideProps or Server Components

If you're using getStaticProps, consider switching to getServerSideProps for pages with frequently changing content, or use React Server Components with the App Router. This fetches data on-demand rather than bundling it all into the page payload.

Why This Matters

That 1.16 MB warning means Next.js is serializing all 137 posts into the initial HTML payload, which:

  • Slows down page load and Time to Interactive (TTI)
  • Hurts SEO and Core Web Vitals
  • Wastes bandwidth for users who may never click "load more"

By fetching only 6 posts initially and loading more on-demand, you'll likely reduce that payload to under 128 kB and significantly improve performance. The combination of GROQ pagination and proper data fetching patterns (API routes, Server Actions, or getServerSideProps) will give you a much more performant solution.

Show original thread
11 replies

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?