Gatsby is in maintenance mode: no new features, a thinning plugin ecosystem, and a Gatsby Cloud that shut down in September 2023. But "maintenance mode" is not "dead", and a lot of Gatsby 4 and 5 sites are going to keep running for years. This is the playbook we use to keep them building safely in 2026: Node compatibility, lockfile discipline, patching transitive dependencies, replacing dead plugins, and CI builds without Gatsby Cloud.
1. Know which Node you can run
Node is the thing most likely to break a Gatsby build that "nobody touched". The constraints:
| Gatsby major | Minimum Node (per Gatsby) | Practical guidance in 2026 |
|---|---|---|
| Gatsby 5 | 18 | Run on Node 20 or 22. Node 18 is end-of-life; Node 20 reached end-of-life in April 2026, so plan on 22. Test Node 24 before adopting it. |
| Gatsby 4 | 14.15 | Upgrade to Gatsby 5 first if at all possible; otherwise pin Node 18 and accept that the runtime is unsupported. |
| Gatsby 3 or earlier | 12.13 | Treat as a rescue and upgrade project, not a maintenance one. |
Check the Node release schedule at github.com/nodejs/release rather than relying on memory; it moves every April and October.
Pin the version everywhere it can drift:
// package.json
{
"engines": { "node": "22.x" },
"packageManager": "npm@10.9.2"
}
echo "22" > .nvmrc
Add engine-strict=true to .npmrc so a wrong Node fails fast on install instead of twenty minutes into a build. Set the same version in your host's build settings (Netlify's NODE_VERSION, Amplify's build image, Vercel's project settings), because the host default will move without asking you.
2. Treat the lockfile as production code
A Gatsby site's dependency tree is large and old. The lockfile is the only thing that makes it reproducible.
- Commit
package-lock.json(oryarn.lock/pnpm-lock.yaml) and never delete it to "fix" an install. - Install with
npm ciin CI, nevernpm install.npm cifails if the lockfile andpackage.jsondisagree, which is the failure you want. - Upgrade dependencies deliberately, in small PRs, with a build and a visual check per PR.
A useful guard in CI:
# .github/workflows/build.yml
name: build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npx gatsby build
env:
GATSBY_CPU_COUNT: 2
- run: test -f public/index.html
3. Patch what you can, document what you cannot
npm audit on a Gatsby 5 site will report vulnerabilities. Some are real, many are in build-time-only tooling, and a few cannot be fixed without a plugin author who is no longer publishing. The process:
- Run
npm audit --omit=devfirst. Anything in the production bundle matters most; for a static site that is often nothing, because the output is HTML. - For fixable transitive dependencies, use
overridesinpackage.jsonto force a patched version without forking the plugin:
{
"overrides": {
"semver": "^7.6.3",
"ws": "^8.18.0"
}
}
- Rebuild and smoke-test after every override. Gatsby's webpack 5 build is sensitive to version jumps in
babel,postcss, andsharp. - For anything you cannot fix, write it down: package, advisory, why it does not affect a static build, date reviewed. Auditors and customers accept a reasoned exception; they do not accept silence.
4. Fix sharp once and for all
Image processing is the most fragile part of a legacy Gatsby build. gatsby-plugin-sharp, gatsby-transformer-sharp, and gatsby-plugin-image all depend on sharp, and a mismatch between the versions they resolve to will produce errors like "Something went wrong installing the sharp module" or segfaults on CI.
Force a single version:
{
"overrides": {
"sharp": "0.33.5"
}
}
Then clear and reinstall:
rm -rf node_modules .cache public
npm ci
npm ls sharp # should show exactly one version
If the build still fails on the host but not locally, the host's build image is the difference; pin the image or switch to a container build you control.
5. Replace dead plugins
Plugins that depended on services that no longer exist will fail or hang, sometimes silently. Check for and remove:
gatsby-plugin-gatsby-cloudand anygatsby-cloudscripts or preview webhooks.- Source plugins for SaaS products that have shut down or changed their API.
- Analytics plugins for retired products (Universal Analytics stopped processing data in 2023; use
gatsby-plugin-google-gtagwith a GA4 measurement id or a plain script tag). gatsby-plugin-offlineunless you have a specific reason to keep a service worker; stale service workers are a common cause of "users see the old site" reports after a deploy.
For a plugin that is unmaintained but still works, vendor it: copy it into plugins/ in your repo so a future registry change cannot remove it from under you. Gatsby loads local plugins from that directory automatically.
6. Upgrade Gatsby 4 to 5 if you are still on 4
If you are on Gatsby 4, the single highest-value maintenance task is upgrading to Gatsby 5 while the upgrade guide and plugin versions still line up. The official guide at gatsbyjs.com is accurate; the main work is:
npm install gatsby@latest react@18 react-dom@18
npm install gatsby-plugin-image@latest gatsby-plugin-sharp@latest gatsby-transformer-sharp@latest gatsby-source-filesystem@latest
Then fix the breaking changes the guide lists: GraphQL schema changes to sort and aggregation fields (sort: { fields: [date], order: DESC } becomes sort: { date: DESC }), the removal of gatsby-plugin-gatsby-cloud features, and React 18 rendering differences. Build, diff the HTML output of a few pages against the old build, and you are done.
7. Build without Gatsby Cloud
Gatsby Cloud's incremental builds are gone, so full builds on generic CI are the norm. Keep them fast enough to live with:
- Cache
.cacheandpublicbetween CI runs (actions/cachekeyed on the lockfile hash). Gatsby can reuse them for partial rebuilds when the content source supports it. - Set
GATSBY_CPU_COUNTto match the runner; the default can over-subscribe small runners and slow builds down. - Keep development-only plugins (bundle analysers, draft previews) out of the production
gatsby-configby gating them onprocess.env.NODE_ENV; every plugin runs on every build. - Deploy with the host's adapter (
gatsby-adapter-netlifyon Netlify) so redirects and headers keep working without Gatsby Cloud.
When maintenance stops being enough
A maintained Gatsby site is a perfectly reasonable thing to run in 2026. It stops being reasonable when you are spending more time on overrides than on content, when a plugin you depend on has no replacement, or when a Node end-of-life forces a runtime Gatsby has never been tested on. At that point the fix is a planned migration, not another patch; see our Gatsby migration service. Until then, our maintenance and rescue retainer exists for exactly this work.