DEV Community

websilvercraft
websilvercraft

Posted on

What’s the `Request` object in the browser, Cloudflare, and Node?

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)
Enter fullscreen mode Exit fullscreen mode
  • 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')
    }
  }
Enter fullscreen mode Exit fullscreen mode
  • Node.js (v18+) Node ships a Fetch implementation (via undici) and sets Request as a global alongside fetch, Response, and Headers. 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)
Enter fullscreen mode Exit fullscreen mode

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"]
  }
}
Enter fullscreen mode Exit fullscreen mode

A tiny sanity check

console.log(typeof Request)           // "function" in all three
console.log(globalThis.Request === Request) // true
Enter fullscreen mode Exit fullscreen mode

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)