runtime:http

An HTTP/1.1 and HTTP/2 server: serve((request) => response). The handler takes a web Request and returns a web Response — the same Fetch API objects fetch uses.

Capability: NetListen

Exposed as an ES module under the runtime: scheme. Status: Available.

All I/O is async

A handler error or a non-Response return becomes a 500. Request and response bodies stream with backpressure; string/byte bodies use the buffered fast path (Content-Length). HTTP/1.1 and HTTP/2 are both served on one port — ALPN over TLS, h2c by prior knowledge on cleartext — and the version never reaches the handler. TLS terminates in-process with secureTransport: "on". See the HTTP server guide for patterns and examples.

Functions

FunctionTypeDescriptionExample
serve(handler)(Handler) => ServerStart a server on an ephemeral port (read it from server.addr). handler is (request) => response.serve((req) => new Response("hi"))
serve(options, handler)({ hostname?, port?, secureTransport?, cert?, key?, alpn?, timeouts? }, Handler) => ServerStart a server bound to options. hostname defaults to 0.0.0.0; port 0 picks an ephemeral port. secureTransport: "on" terminates TLS (needs inline PEM cert + key; alpn defaults to ["h2", "http/1.1"]). timeouts bounds connections that stall — see below.serve({ port: 443, secureTransport: "on", cert, key }, handler)

Serve

JavaScript
import { serve } from "runtime:http";

// The handler takes a web Request and returns a web Response —
// the same Fetch API objects fetch() uses.
const server = serve({ port: 8080 }, async (request) => {
  const url = new URL(request.url);
  if (url.pathname === "/echo") {
    return new Response(await request.text(), { status: 200 });
  }
  return Response.json({ method: request.method, path: url.pathname });
});

const { hostname, port } = await server.addr;
console.log(`listening on http://${hostname}:${port}`);

Timeouts

timeouts bounds connections that are idle or stalled. A request in flight, a body still arriving, and a response still streaming are never interrupted.

KeyDefaultBounds
handshake10000Accept → ready to carry requests: the TLS handshake, and the wait for the first byte
headerRead30000A request head arriving in full; on HTTP/1.1 also the idle keep-alive limit
h2KeepAlive20000PING probes on an idle HTTP/2 connection; a dead peer goes within twice this

Each is a number of milliseconds. null disables one, omitting it keeps the default, and a non-number is a TypeError at the call rather than a bound port.

JavaScript
serve({ port: 8080, timeouts: { headerRead: 5000, h2KeepAlive: null } }, handler);

Bodies

DirectionReadableStreamstring / bytes
Requestrequest.body pulls chunks as they arriverequest.text() / .json() / .arrayBuffer() materialize the full body
ResponseChunked transfer-encoding, backpressuredContent-Length buffered fast path

Lifecycle

serve() returns a Server immediately; the accept loop runs in the background.

JavaScript
const server = serve(handler);          // ephemeral port
const { port } = await server.addr;     // resolved once listening
// … handle requests …
await server.stop();                    // stop accepting; finished resolves

Server

MemberTypeDescription
addrPromise<{ hostname, port }>The bound address; resolves once the server is listening.
finishedPromise<void>Resolves when the accept loop has ended (after stop()).
stop()Promise<void>Stop accepting and shut down; resolves once stopped.

Errors

ErrorWhen
TypeErrorThe serve() handler isn't a function; secureTransport is "on" without both cert and key, or is a value other than "on"/"off"; or a Request / Response is built with an invalid init (the Fetch API's own checks).
Errorcode "ERR_TLS" — the cert or key could not be parsed. Raised by serve() itself, so a bad cert never becomes a port that rejects every handshake.
DOMExceptionname "NotAllowedError" — the NetListen capability is not granted.

See also

Last updated on
Edit this page