The Blazing-Fast Promise
Let’s start with why we’re all here: Gatsby is supposed to be fast. Ridiculously fast. As a static site generator, it does the heavy lifting at build time, compiling your React components and data sources into a folder of plain HTML, CSS, and JavaScript
files. When a user visits your site, the server just sends over a pre-built HTML file. There’s no database to query, no server-side rendering to wait for. This is the core of the Jamstack architecture, and it delivers incredible initial page load speeds. This process gives you a high-performance foundation out of the box. Your site gets a near-perfect Google Lighthouse score on the first try, and you feel like a web performance champion. But the story doesn’t end with that first HTML paint. After the static page loads, Gatsby “hydrates” into a full-fledged React app, making the site dynamic and interactive. And it’s during this hydration step that the hidden performance trap springs shut.
Unmasking the Culprit: Bloated `page-data.json`
The trap is a file you might not even know you're shipping to your users: `page-data.json`. For every page Gatsby builds, it also creates a corresponding JSON file in the `public/page-data` directory. This file contains the results of the GraphQL page query you wrote for that page. When a user navigates from one page to another within your site, Gatsby fetches this JSON file in the background to get the data needed for the next page, enabling near-instant transitions without a full page reload.
Here’s the problem: if your GraphQL query is greedy, that `page-data.json` file can become enormous. We’re talking megabytes of data for a single page. When that happens, two things go wrong. First, the client has to download this massive JSON file, which can be slow on poor connections. Second, Gatsby has to parse all that data and use it to hydrate the page, causing a spike in main-thread work that freezes the browser and delays interactivity. Your “blazing-fast” static site suddenly feels sluggish and unresponsive.
How We Fall Into the Trap
This isn't a rookie mistake; it's an easy oversight for even experienced developers. It usually happens when dealing with images and complex data structures. A developer might write a GraphQL query to fetch, say, a list of blog posts for an index page. To be safe, they query for *all* available fields on each post: the title, slug, excerpt, author details, and the entire image object from a CMS, which might include dimensions, alt text, and a dozen different URL variations.
While GraphQL makes it easy to ask for exactly what you need, it's just as easy to ask for everything. The developer’s thinking is, “I’ll just grab it all now in case I need it later.” But the page component only uses the title, slug, and a single thumbnail. The rest of that data—especially the heavy, unoptimized image data—gets packed into `page-data.json` for no reason. This is particularly common when developers don't properly leverage `gatsby-plugin-image`, which is designed to handle image optimization and querying via special GraphQL fragments, ensuring you only fetch the data needed for a responsive, optimized `GatsbyImage` component.
The Fix: Query with Precision
Fixing this trap requires discipline and a shift in mindset. You have to treat your page data budget as carefully as your JavaScript bundle size. The solution is twofold:
1. **Audit Your Queries:** Go through each of your page and static queries. Look at the data you’re requesting and compare it to the data you’re actually using in your components. If a field isn't rendered, remove it from the query. Be ruthless. Every extra field adds weight to `page-data.json`.
2. **Embrace `gatsby-plugin-image`:** For images, stop querying for raw URLs or complex image objects from your CMS. Instead, use the GraphQL fragments provided by `gatsby-plugin-image`, like `GatsbyImageSharpFluid` or `GatsbyImageSharpFixed`. These fragments tell Gatsby to perform its powerful image processing magic at build time and only embed the critical data needed to render a responsive, lazy-loaded image. Your query becomes cleaner, and your `page-data.json` file shrinks dramatically because it no longer contains bulky, raw image data.
By being intentional with your data-fetching, you ensure that the JSON file contains only the essentials, keeping it small and fast to download and parse.











