Cut Gatsby Build Times in Half with Deferred Static Generation
Gatsby's Deferred Static Generation skips HTML generation for low-traffic pages at build time, rendering them on first request instead. Cut build times 50-80% for large sites — if your host supports on-demand functions.
25 Oct 2025, 11:58 UTC

The problem: builds that never finish
You've got a Gatsby site with 15,000 product pages. gatsby build takes 45 minutes on CI, and every new SKU adds another 30 seconds. Most of those pages get visited once a month — if that. You're paying for build minutes nobody sees.
Deferred Static Generation (DSG) solves this by skipping HTML generation for low-traffic pages during the initial build. Instead, the first request triggers a serverless function that renders the page on-demand, then caches it as a static asset for all subsequent visits. The result: a 50–80% build-time reduction for large sites, with no runtime penalty after the first hit.
How DSG differs from traditional static and ISR
Standard Gatsby builds every page at compile time. Next.js Incremental Static Regeneration (ISR) rebuilds pages in the background after a timeout. DSG is simpler: zero HTML at build time, one serverless render on first request, then permanent static cache. No revalidation loops, no stale-while-revalidate config.
The catch: your hosting platform must support on-demand rendering. Gatsby Cloud, Netlify (with @netlify/plugin-gatsby), and Vercel (with the Gatsby adapter) all provide this. Traditional static hosts (S3 + CloudFront, GitHub Pages) cannot run the serverless function, so DSG pages will 404.
Marking pages as deferred
In gatsby-node.js, add defer: true to the page context when calling createPage:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
allProduct {
nodes {
slug
isPopular
}
}
}
`)
result.data.allProduct.nodes.forEach(product => {
createPage({
path: `/product/${product.slug}`,
component: require.resolve('./src/templates/product.js'),
context: {
slug: product.slug,
defer: !product.isPopular // defer long-tail pages
}
})
})
}
Alternatively, use gatsby-plugin-defer to apply rules via configuration (e.g., defer all paths under /archive/ or pages older than 90 days). The plugin sets defer: true automatically during onCreatePage.
What actually happens at build vs. request time
During gatsby build, Gatsby still runs all GraphQL queries for every page — including deferred ones. It writes a JSON manifest to public/deferred/ containing the query results and component metadata, but no HTML. The build output shows these pages as "deferred" when you run gatsby build --log-pages.
On first request, the platform's edge function reads the manifest, executes the page's React component with the pre-fetched data, streams the HTML to the client, and writes the rendered HTML to the static cache (usually a bucket or edge KV store). Subsequent requests serve the cached HTML directly — zero function invocation.
Worked example: 12,000-page documentation site
A team migrated a versioned docs site (12k pages across 8 versions) to DSG. They marked all pages except the latest version's top 200 as deferred. Build time dropped from 38 minutes to 9 minutes on Netlify. Cold-start latency for a deferred page averaged 1.2s (measured via x-nf-request-id headers). After first visit, TTFB fell to ~40ms.
Key config in netlify.toml:
[functions]
node_bundler = "esbuild"
included_files = ["public/deferred/**/*"]
[[plugins]]
package = "@netlify/plugin-gatsby"
[plugins.inputs]
deferPages = true
They verified behavior by deploying to a Netlify branch deploy, visiting a deferred URL, and checking the function logs for "Generating deferred page" messages.
Trade-offs you'll live with
- Cold-start latency: 1–3 seconds on first visit. Unacceptable for landing pages, checkout flows, or any SEO-critical entry point that must be instant. Keep high-value pages non-deferred.
- GraphQL timeout risk: Expensive queries that pass at build time (where limits are generous) may hit the serverless function's 10–30s timeout. Profile query complexity with
gatsby build --profilebefore deferring. - No local simulation:
gatsby developrenders all pages immediately. You must test on a staging deploy with a supported platform. - Cache invalidation: Redeploy clears the entire deferred cache. Gatsby Cloud offers selective purge via webhook; Netlify/Vercel require full redeploy to refresh deferred content.
- Analytics blind spot: Crawlers and A/B tools won't see deferred pages until first visit. If you rely on deploy-time sitemap generation, deferred pages won't appear until rendered.
When to reach for DSG — and when to skip it
Use DSG when you have >5k pages, a clear long-tail traffic pattern, and a hosting platform that supports on-demand functions. Skip it if your site is under 2k pages (build time is already fast), you're on a static-only host, or every page is mission-critical for first-visit latency.
Start by auditing your page traffic with gatsby build --log-pages and your analytics. Mark the bottom 80% by traffic as deferred, deploy to a branch, and measure. If build time drops >40% and cold starts stay under 2s for your audience, you've found the sweet spot.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.