TypeError: fetch is not defined is a version-and-environment problem more than a code bug — fetch() is a browser API that Node.js only started supporting natively in relatively recent versions, so this error is almost always either an older Node runtime, or code being shared between browser and Node contexts without accounting for the difference.
This error means you called fetch() in a Node.js environment where it isn't available as a global — either because your Node.js version predates native fetch support, or because you're running in a context (certain older bundler configurations, some testing environments) that doesn't polyfill or provide it.
Why This Error Happens
fetch() was standardized as a Web API for browsers first; Node.js added native, global fetch support starting in Node 18 (experimental) and stabilized it in Node 21. Any Node.js process running on an older version, or a restricted execution context that doesn't include the global, will throw this error the moment fetch is referenced — since it genuinely doesn't exist as a global in that environment, distinct from a typo or an import issue.
Reproducing the Error
Running on an older Node.js version:
// server.ts
async function getData() {
const response = await fetch("https://api.example.com/data");
return response.json();
}
// TypeError: fetch is not defined
// (on Node.js < 18, or 18/20 without the --experimental-fetch flag depending on exact version)
Checking your actual Node.js version, since this is the most direct diagnostic:
node --version
# v16.x.x or v17.x.x — fetch not available natively
Core Concepts Behind This Error
Node.js version determines native fetch availability directly — Node 18 introduced it behind an experimental flag in early minor versions (stabilizing within the 18.x line), and Node 21+ has it fully stable without any flag; checking your actual runtime version is the fastest way to know whether native support should even be expected.
Deployment and CI environments can run a different Node.js version than local development, silently causing this error in one environment but not another — a package.json engines field or a .nvmrc/version-pinning file helps keep versions consistent, but doesn't automatically prevent a mismatch if your deployment platform doesn't respect it.
node-fetch (a popular polyfill package) is still commonly present in older codebases and dependency trees, and mixing it with native fetch (once you upgrade Node) can cause confusing behavior differences, since they're not perfectly identical implementations — a codebase upgrading Node versions should deliberately decide whether to keep or remove the node-fetch dependency, not leave both in play accidentally.
Some restricted execution environments (certain serverless runtimes, specific testing environments configured without DOM/Web API globals) may not expose fetch even on a Node version that otherwise supports it — this is a narrower case worth checking specifically if you've confirmed your Node version should have native support but still hit the error.
Fixing "fetch Is Not Defined"
Fix 1: Upgrade to Node.js 18+ (ideally 20+ LTS or later) for native fetch support, the most direct and generally correct fix for new or actively maintained projects:
nvm install 20
nvm use 20
node --version # confirm v20.x.x or later
Fix 2: If upgrading Node isn't immediately possible, install and import a fetch polyfill explicitly:
pnpm add node-fetch
import fetch from "node-fetch"; // explicit import for older Node versions
async function getData() {
const response = await fetch("https://api.example.com/data");
return response.json();
}
Fix 3: Pin your Node.js version explicitly across environments to avoid inconsistent behavior, ensuring local, CI, and production all use a version with native fetch support:
// package.json
{ "engines": { "node": ">=20.0.0" } }
# .nvmrc
20
Should You Use node-fetch Even on Node Versions With Native Support?
Generally no — once your minimum supported Node version has stable native fetch, remove the node-fetch dependency and use the global directly, since maintaining an unnecessary dependency adds install size and a potential source of subtly different behavior versus the native implementation. Keep node-fetch only if you genuinely need to support older Node versions across your deployment targets and can't yet require the newer minimum.
Preventing This Error in Production
Pin a minimum Node.js version explicitly (via engines in package.json and a .nvmrc or equivalent) across local, CI, and production environments, so version mismatches surface as a clear, early configuration issue rather than a confusing runtime error. When upgrading Node versions specifically to drop a fetch polyfill dependency, remove the polyfill deliberately rather than leaving both native and polyfilled fetch available, which can mask version-specific behavior differences.
If you hit this error, check node --version first — it resolves the majority of cases immediately, pointing you toward either an upgrade or a polyfill depending on what your deployment constraints actually allow.