Node "ReferenceError: fetch is not defined" on older Node in CI
Global fetch landed in Node 18 (and is stable in 21+). On a runner using Node 16 or earlier, fetch is undefined, so any call throws a ReferenceError.
What this error means
A call to fetch(...) fails with "ReferenceError: fetch is not defined", typically only on CI where the Node version differs from the developer machine.
node
const res = await fetch('https://api.example.com/health');
^
ReferenceError: fetch is not definedCommon causes
Runner uses Node older than 18
Global fetch is not available before Node 18, so the call references an undefined global.
Node version drift between local and CI
Local Node has fetch but the CI runner pins an older version, so only CI fails.
How to fix it
Pin a Node version with built-in fetch
Set the runner to Node 18 or newer so fetch is a global.
.github/workflows/ci.yml
- uses: actions/setup-node@v4
with:
node-version: '20'Polyfill fetch on legacy Node
If you must stay on an older Node, install undici and assign its fetch to the global.
index.js
import { fetch } from 'undici';
globalThis.fetch = fetch;How to prevent it
- Pin the CI Node version with an
.nvmrcorenginesfield. - Keep local and CI Node versions aligned.
- Polyfill only when you cannot upgrade the runtime.
Related guides
Node "ReferenceError: structuredClone is not defined" in CIFix Node "ReferenceError: structuredClone is not defined" in CI - the structuredClone global was added in Nod…
Node "DeprecationWarning: punycode module is deprecated" (DEP0040) in CIFix Node "DeprecationWarning: The punycode module is deprecated" (DEP0040) in CI - a dependency imports the b…
Node "Unsupported engine ... required: node" in CIFix npm "Unsupported engine" / "engine node is incompatible" in CI - the runner Node version does not satisfy…