http
To use the HTTP client-side methods (http.get, http.request, etc.), you must enable the enable_nodejs_http_modules compatibility flag in addition to the nodejs_compat flag.
This flag is automatically enabled for Workers using a compatibility date of 2025-08-15 or later when nodejs_compat is enabled. For Workers using an earlier compatibility date, you can manually enable it by adding the flag to your wrangler.toml:
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_modules"]To use the HTTP server-side methods (http.createServer, http.Server, http.ServerResponse), you must enable the enable_nodejs_http_server_modules compatibility flag in addition to the nodejs_compat flag.
This flag is automatically enabled for Workers using a compatibility date of 2025-09-01 or later when nodejs_compat is enabled. For Workers using an earlier compatibility date, you can manually enable it by adding the flag to your wrangler.toml:
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_server_modules"]To use both client-side and server-side methods, enable both flags:
compatibility_flags = ["nodejs_compat", "enable_nodejs_http_modules", "enable_nodejs_http_server_modules"]An implementation of the Node.js http.get ↗ method.
The get method performs a GET request to the specified URL and invokes the callback with the response. It's a convenience method that simplifies making HTTP GET requests without manually configuring request options.
Because get is a wrapper around fetch(...), it may be used only within an exported
fetch or similar handler. Outside of such a handler, attempts to use get will throw
an error.
import { get } from "node:http";
export default { async fetch() { const { promise, resolve, reject } = Promise.withResolvers(); get("http://example.org", (res) => { let data = ""; res.setEncoding("utf8"); res.on("data", (chunk) => { data += chunk; }); res.on("end", () => { resolve(new Response(data)); }); res.on("error", reject); }).on("error", reject); return promise; },};The implementation of get in Workers is a wrapper around the global
fetch API ↗
and is therefore subject to the same limits ↗.
As shown in the example above, it is necessary to arrange for requests to be correctly
awaited in the fetch handler using a promise or the fetch may be canceled prematurely
when the handler returns.
An implementation of the Node.js `http.request' ↗ method.
The request method creates an HTTP request with customizable options like method, headers, and body. It provides full control over the request configuration and returns a Node.js stream.Writable ↗ for sending request data.
Because request is a wrapper around fetch(...), it may be used only within an exported
fetch or similar handler. Outside of such a handler, attempts to use request will throw
an error.
import { get } from "node:http";
export default { async fetch() { const { promise, resolve, reject } = Promise.withResolvers(); get( { method: "GET", protocol: "http:", hostname: "example.org", path: "/", }, (res) => { let data = ""; res.setEncoding("utf8"); res.on("data", (chunk) => { data += chunk; }); res.on("end", () => { resolve(new Response(data)); }); res.on("error", reject); }, ) .on("error", reject) .end(); return promise; },};The following options passed to the request (and get) method are not supported due to the differences required by Cloudflare Workers implementation of node:http as a wrapper around the global fetch API:
maxHeaderSizeinsecureHTTPParsercreateConnectionlookupsocketPath
The OutgoingMessage ↗ class represents an HTTP response that is sent to the client. It provides methods for writing response headers and body, as well as for ending the response. OutgoingMessage extends from the Node.js stream.Writable stream class ↗.
The OutgoingMessage class is a base class for outgoing HTTP messages (both requests and responses). It provides methods for writing headers and body data, as well as for ending the message. OutgoingMessage extends from the Writable stream class ↗.
Both ClientRequest and ServerResponse both extend from and inherit from OutgoingMessage.
The IncomingMessage class represents an HTTP request that is received from the client. It provides methods for reading request headers and body, as well as for ending the request. IncomingMessage extends from the Readable stream class.
The IncomingMessage class represents an HTTP message (request or response). It provides methods for reading headers and body data. IncomingMessage extends from the Readable stream class.
import { get, IncomingMessage } from "node:http";import { ok, strictEqual } from "node:assert";
export default { async fetch() { // ... get("http://example.org", (res) => { ok(res instanceof IncomingMessage); }); // ... },};The Workers implementation includes a cloudflare property on IncomingMessage objects:
import { createServer } from "node:http";import { httpServerHandler } from "cloudflare:node";
const server = createServer((req, res) => { console.log(req.cloudflare.cf.country); console.log(req.cloudflare.cf.ray); res.write("Hello, World!"); res.end();});
server.listen(8080);
export default httpServerHandler({ port: 8080 });The cloudflare.cf property contains Cloudflare-specific request properties.
The following differences exist between the Workers implementation and Node.js:
- Trailer headers are not supported
- The
socketattribute does not extend fromnet.Socketand only contains the following properties:encrypted,remoteFamily,remoteAddress,remotePort,localAddress,localPort, anddestroy()method. - The following
socketattributes behave differently than their Node.js counterparts:remoteAddresswill return127.0.0.1when ran locallyremotePortwill return a random port number between 2^15 and 2^16localAddresswill return the value of request'shostheader if exists. Otherwise, it will return127.0.0.1localPortwill return the port number assigned to the server instancereq.socket.destroy()falls through toreq.destroy()
A partial implementation of the Node.js `http.Agent' ↗ class.
An Agent manages HTTP connection reuse by maintaining request queues per host/port. In the workers environment, however, such low-level management of the network connection, ports, etc, is not relevant because it is handled by the Cloudflare infrastructure instead. Accordingly, the implementation of Agent in Workers is a stub implementation that does not support connection pooling or keep-alive.
import { Agent } from "node:http";import { strictEqual } from "node:assert";
const agent = new Agent();strictEqual(agent.protocol, "http:");An implementation of the Node.js http.createServer ↗ method.
The createServer method creates an HTTP server instance that can handle incoming requests.
import { createServer } from "node:http";import { httpServerHandler } from "cloudflare:node";
const server = createServer((req, res) => { res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Hello from Node.js HTTP server!");});
server.listen(8080);export default httpServerHandler({ port: 8080 });The httpServerHandler function integrates Node.js HTTP servers with the Cloudflare Workers request model. It supports two API patterns:
import http from "node:http";import { httpServerHandler } from "cloudflare:node";
const server = http.createServer((req, res) => { res.end("hello world");});
// Pass server directly (simplified) - automatically calls listen() if neededexport default httpServerHandler(server);
// Or use port-based routing for multiple serversserver.listen(8080);export default httpServerHandler({ port: 8080 });The handler automatically routes incoming Worker requests to your Node.js server. When using port-based routing, the port number acts as a routing key to determine which server handles requests, allowing multiple servers to coexist in the same Worker.
For more direct control over request routing, you can use the handleAsNodeRequest function from cloudflare:node. This function directly routes a Worker request to a Node.js server running on a specific port:
import { createServer } from "node:http";import { handleAsNodeRequest } from "cloudflare:node";
const server = createServer((req, res) => { res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Hello from Node.js HTTP server!");});
server.listen(8080);
export default { fetch(request) { return handleAsNodeRequest(8080, request); },};This approach gives you full control over the fetch handler while still leveraging Node.js HTTP servers for request processing.
An implementation of the Node.js http.Server ↗ class.
The Server class represents an HTTP server and provides methods for handling incoming requests. It extends the Node.js EventEmitter class and can be used to create custom server implementations.
When using httpServerHandler, the port number specified in server.listen() acts as a routing key rather than an actual network port. The handler uses this port to determine which HTTP server instance should handle incoming requests, allowing multiple servers to coexist within the same Worker by using different port numbers for identification. Using a port value of 0 (or null or undefined) will result in a random port number being assigned.
import { Server } from "node:http";import { httpServerHandler } from "cloudflare:node";
const server = new Server((req, res) => { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ message: "Hello from HTTP Server!" }));});
server.listen(8080);export default httpServerHandler({ port: 8080 });The following differences exist between the Workers implementation and Node.js:
- Connection management methods such as
closeAllConnections()andcloseIdleConnections()are not implemented - Only
listen()variants with a port number or no parameters are supported:listen(),listen(0, callback),listen(callback), etc. For reference, see the Node.js documentation ↗. - The following server options are not supported:
maxHeaderSize,insecureHTTPParser,keepAliveTimeout,connectionsCheckingInterval
An implementation of the Node.js http.ServerResponse ↗ class.
The ServerResponse class represents the server-side response object that is passed to request handlers. It provides methods for writing response headers and body data, and extends the Node.js Writable stream class.
import { createServer, ServerResponse } from "node:http";import { httpServerHandler } from "cloudflare:node";import { ok } from "node:assert";
const server = createServer((req, res) => { ok(res instanceof ServerResponse);
// Set multiple headers at once res.writeHead(200, { "Content-Type": "application/json", "X-Custom-Header": "Workers-HTTP", });
// Stream response data res.write('{"data": ['); res.write('{"id": 1, "name": "Item 1"},'); res.write('{"id": 2, "name": "Item 2"}'); res.write("]}");
// End the response res.end();});
export default httpServerHandler(server);The following methods and features are not supported in the Workers implementation:
assignSocket()anddetachSocket()methods are not available- Trailer headers are not supported
writeContinue()andwriteEarlyHints()methods are not available- 1xx responses in general are not supported
Because the Workers implementation of node:http is a wrapper around the global fetch API, there are some differences in behavior and limitations compared to a standard Node.js environment:
Connectionheaders are not used. Workers will manage connections automatically.Content-Lengthheaders will be handled the same way as in thefetchAPI. If a body is provided, the header will be set automatically and manually set values will be ignored.Expect: 100-continueheaders are not supported.- Trailing headers are not supported.
- The
'continue'event is not supported. - The
'information'event is not supported. - The
'socket'event is not supported. - The
'upgrade'event is not supported. - Gaining direct access to the underlying
socketis not supported.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark