Skip to content
Latchkey

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 defined

Common 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 .nvmrc or engines field.
  • Keep local and CI Node versions aligned.
  • Polyfill only when you cannot upgrade the runtime.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →