+1 (415) 779-8456

Keeping a Legacy Gatsby Site Alive in 2026

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 majorMinimum Node (per Gatsby)Practical guidance in 2026
Gatsby 518Run 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 414.15Upgrade to Gatsby 5 first if at all possible; otherwise pin Node 18 and accept that the runtime is unsupported.
Gatsby 3 or earlier12.13Treat 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 (or yarn.lock / pnpm-lock.yaml) and never delete it to "fix" an install.
  • Install with npm ci in CI, never npm install. npm ci fails if the lockfile and package.json disagree, 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:

  1. Run npm audit --omit=dev first. Anything in the production bundle matters most; for a static site that is often nothing, because the output is HTML.
  2. For fixable transitive dependencies, use overrides in package.json to force a patched version without forking the plugin:
{
  "overrides": {
    "semver": "^7.6.3",
    "ws": "^8.18.0"
  }
}
  1. Rebuild and smoke-test after every override. Gatsby's webpack 5 build is sensitive to version jumps in babel, postcss, and sharp.
  2. 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-cloud and any gatsby-cloud scripts 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-gtag with a GA4 measurement id or a plain script tag).
  • gatsby-plugin-offline unless 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 .cache and public between CI runs (actions/cache keyed on the lockfile hash). Gatsby can reuse them for partial rebuilds when the content source supports it.
  • Set GATSBY_CPU_COUNT to 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-config by gating them on process.env.NODE_ENV; every plugin runs on every build.
  • Deploy with the host's adapter (gatsby-adapter-netlify on 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.