I’ve been building a tiny API with itty-router that I want to run unchanged on Cloudflare Workers and a plain Node server. itty is fetch-native—it speaks in terms of fetch(req)
, Request
, and Response
. That’s awesome for portability, but it also means the whole trick hinges on the Request
object being consistent across runtimes.
Before I wired everything up, I needed to check if I can use on the same Request objects in cloudflare and node environments.
The Request
to use with fetch
is part of the WHATWG Fetch Standard—a web platform spec that defines fetch
, Request
, Response
, Headers
, etc. All three environments expose the same API surface (with minor runtime quirks), so code written against the spec tends to work everywhere.
Where it comes from
-
Browser
Request
is a built-in global provided by the browser. No imports.
const req = new Request('/api', { method: 'POST' })
const res = await fetch(req)
-
Cloudflare Workers
Workers implement the same Fetch standard.
Request
is global here too.
export default {
async fetch(req) {
// req is already a Request
return new Response('ok')
}
}
-
Node.js (v18+)
Node ships a Fetch implementation (via undici) and sets
Request
as a global alongsidefetch
,Response
, andHeaders
. You don’t need to import anything.
// Node 18+:
const req = new Request('https://example.com')
const res = await fetch(req)
console.log(res.status)
Why you don’t import it in Node
Because Node 18+ defines Request
on globalThis
just like the browser/Workers. Older Node versions didn’t have it—you had to polyfill (e.g., node-fetch
or undici
). On current Node, it’s simply available.
TypeScript tip
For Node projects, add DOM libs so the Request
type is known at compile time:
// tsconfig.json
{
"compilerOptions": {
"lib": ["ES2022", "DOM"]
}
}
A tiny sanity check
console.log(typeof Request) // "function" in all three
console.log(globalThis.Request === Request) // true
When streams are involved there are a few practical differences, even though both runtimes expose the same Fetch API. For example, in Node, if you construct a Request
from a Node stream, you’ll include duplex: 'half'
in the init. For ordinary JSON bodies/strings, you can ignore this. Details about the streams related fidderences, in the next post: Same Fetch, Different Streams: duplex: 'half' in Node vs Cloudflare Workers.
Top comments (0)