Gatsby in 2022: Beyond Static Sites
Gatsby has changed substantially over the past two years. If you last looked at the framework in its Gatsby 2 days, the current Gatsby 4 feature set may come as a surprise. The core static-site approach is still there, but Gatsby now offers server-side rendering, deferred static generation, and serverless functions, among other capabilities. When I recently upgraded my personal site from Gatsby 2 to Gatsby 4, I used several of these new features in different combinations depending on the data needs of each page section.
Server-Side Rendering for Dynamic Data
Gatsby 4 added support for server-side rendering (SSR), which I used for the dashboard section of my site. SSR is a good fit for data that changes frequently and needs to be fetched at request time. My dashboard relies on three SSR-backed features, each pulling from a different data source.
- All Reactions: Reaction data is fetched from a Fauna database and rendered in an interactive accordion component. The reactions are grouped by type and listed by page slug, each with its own count.
- Visitors By Country: This data comes from the Google Analytics Data API (GA4) and shows the number of visits per country in descending order.
- Visitors By Location: This is served by the older Google Analytics Core Reporting API (UA), which is slated for deprecation. The location coordinates from that API are plotted on an interactive 3D globe built with three.js and @react-three/fiber, with orbit controls from @react-three/drei.
One notable limitation: the GA4 API does not currently expose the latitude and longitude needed to plot individual locations on the globe, which is why the visitors-by-location view still relies on the older UA API. There is an open issue requesting this feature in the GA4 developer tools repository.
SSR also means the HTML sent to the browser is complete. The country list and rendered HTML work even with JavaScript disabled. The three.js globe, however, requires JavaScript, so it won't render without it.
Combining SSR With Client-Side Requests
A pure SSR approach has a downside: the data is only fresh when the page first loads. If a database record changes afterward, a visitor won't see the update without a manual page refresh. For the latest reactions section on my dashboard, I combined SSR with client-side request logic to keep the data current.
With JavaScript enabled, the browser polls a Gatsby serverless function every 60 seconds to retrieve the most recent reaction from the Fauna database. The displayed "latest reaction" is therefore never more than a minute old, and the page updates without any user interaction. If JavaScript is turned off, the identity of the latest reaction still gets rendered server-side, so the section isn't blank.
Mixing SSR With Static Generation
Not all dynamic-looking content requires server work at request time. Some site changes happen only when you publish new content yourself — you write a post, commit the Markdown file, and trigger a fresh build. For my analytics charts, I created a hybrid where the page itself is SSR-rendered but the chart data is statically generated.
I built four hand-crafted data visualizations — a donut chart, a line chart, a bar chart, and a radar chart — using only math, SVG elements, and references to tutorials. None of the charts relies on a third-party charting library.
- A donut chart counting posts published each month over the past four years
- A line chart showing how many posts were published on each day of the week
- A bar chart tracking which external publications I've written for and how often
- A radar chart displaying the total count for each tag used across posts and articles
The chart data is pulled from frontmatter inside my .mdx files and queried from Gatsby's data layer using GraphQL. Since every content commit starts a new Gatsby Cloud build, these "static" views are effectively updated as frequently as the site itself. The data can't drift out of sync mid-view. Hand-coding the SVG rendering gave me finer control over the final styling than previous experiences with chart libraries, and it also means everything renders without client JavaScript.
Deferred Static Generation and Build Speed
One traditional Gatsby pain point is build time. With static site generation, every page must be built ahead of deployment. That typically serves content fast with good SEO, but as content grows or many editors contribute, each build gets slower.
Gatsby 4 introduced deferred static generation (DSG) to respond to that problem. DSG produces the exact same kind of output as SSG when the page has been visited: a pre-built HTML page cached server-side and delivered instantly to all subsequent visitors. The difference is in timing. When you use DSG, Gatsby skips building that page at deploy time. It builds the page just-in-time on the first user visit, then stores it in the cache for everyone after that.
This is the critical difference from SSR. In SSR, each visitor triggers a server round-trip to generate the page before it gets sent to the browser. Teams often try to counteract this with layers of caching headers, which can lead to maintenance headaches. DSG intentionally keeps the output cachable so one visitor is enough to warm the page for everyone.
When is deferring the right move? Many Gatsby users look at analytics and defer the pages that see little traffic. Deferring older posts or product pages that change rarely also helps. Also possible: defer pages or posts based on the date the content went live.
The change is small — in the createPage API you just add one property:
// In pages that haven't been visited yet, defer until the first request.
// Other pages build up front as usual.
Let's imagine a typical blog: you want the newest 100 posts built at deploy time, but you'd happily defer all the older content that gets less traffic. Assuming posts are already sorted by date, you can apply a similar condition to the defer flag during createPage. The same idea applies to the File System Route API.
The gains can be substantial. Depending on site structure and the number of deferred pages, some teams report cutting their production builds by more than half — which is meaningful when you're waiting on a release later that afternoon.
Serverless Functions for Event Handling
Capturing reactions on my content pages relies on a small client-to-server interaction. I display a set of SVG emojis for reaction types. A click posts a payload to a Gatsby serverless function, and that function stores the event securely in Fauna. This keeps database credentials out of the browser and uses a relatively small amount of function code. Because these functions live alongside the rest of the Gatsby project, the full workflow — static content plus server-side handlers — stays in one repository.
New Framework APIs Worth Knowing
Gatsby 4.15.0 introduced the Script API, which brings a notable off-main-thread loading strategy. Powered by Builder.io's Partytown, this strategy allows third-party scripts — Google Analytics being a common example — to run in a Web Worker instead of blocking the main thread. Moving that work off the critical path is a straightforward way to shave time off page loads.
Starting with release 4.19.0, the framework also includes the Head API. For years, managing document metadata in Gatsby meant pulling in react-helmet and gatsby-plugin-react-helmet. That's no longer a requirement: the Head API covers this functionality natively, and migrating existing code is a fairly mechanical process.
A Slices API is also in the works. An open RFC is available for discussion on the Gatsby GitHub repository.
What Gatsby Cloud Actually Delivers
Gatsby remains a free, open-source framework that can run on any host. Gatsby Cloud is pitched as the option that removes configuration friction — no extra plugins needed — and it's where the build performance story gets interesting.
To give a concrete sense of what that means, consider a site of roughly 110 pages, all composed in .mdx. Those pages include syntax-highlighted code blocks, embedded images, Tweets, Code Sandboxes, and YouTube videos — all of which inflate transform times compared with plain Markdown. Measured on the free tier of Gatsby Cloud (with Pro mode active during a 14-day trial), the results were:
Reading from the bottom up:
- Triggered by Gatsby Cloud:
03.22— the first deployment, a cold-cache build. - Triggered by a manual Build:
03.48— a manual, cold-cache build. - test: content change 1:
55s— triggered by a GitHub commit that touched one post, built from a warm cache.
The cold-cache numbers are expected to be slower; Gatsby Cloud has no prior state to diff against. Once a cache exists, its incremental engine kicks in and the warm-cache figure of 55 seconds for a content change is the one that matters for day-to-day work.
From SSG to Reactive Site Generator
Gatsby's CTO has made the case that the project has outgrown the "static site generator" label entirely. The term now is Reactive Site Generator (RSG). The distinction isn't cosmetic. When a Gatsby 4 site runs on Netlify or Vercel, it behaves like an SSG. On Gatsby Cloud, it behaves reactively: regenerating a static page can be up to 100x faster when content changes.
The practical demonstration is a reactively generated static page deployed in roughly 2 seconds from a single button push. CMS previews have long been able to do something similar, but never at that speed.
For anyone whose Gatsby experience stops at version 2, the current framework is a markedly different product. Newer rendering modes — including DSG and SSR — plus the APIs above make it more flexible, and Gatsby Cloud turns the build-time complaint into a non-issue for most projects.



