Networking#
Modern JavaScript runtimes (Node, Deno, Bun) and browsers share the same
fetch API for HTTP, plus runtime-specific lower-level APIs.
fetch#
The standard HTTP client; works in browsers, Deno, Bun, and Node 18+.
const res = await fetch("https://api.example.com/users/1");
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const user = await res.json();
POST with JSON.
await fetch("https://api.example.com/users", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ name: "operator" }),
});
Streaming, timeouts, and cancellation use AbortController:
const ac = new AbortController();
setTimeout(() => ac.abort(), 5000);
const res = await fetch(url, { signal: ac.signal });
for await (const chunk of res.body) {
process(chunk);
}
Node HTTP Modules#
import http from "node:http";
const server = http.createServer((req, res) => {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({ ok: true }));
});
server.listen(8080);
For HTTPS use node:https; for HTTP/2 use node:http2.
TCP / UDP / Unix Sockets#
import net from "node:net";
const server = net.createServer((conn) => {
conn.write("hello\n");
conn.on("data", (b) => conn.write(b));
}).listen(9000);
const client = net.createConnection({ port: 9000 }, () => {
client.write("hi");
});
UDP via node:dgram; Unix domain sockets by passing a path option to
net.createServer / net.createConnection.
WebSockets#
In browsers.
const ws = new WebSocket("wss://example.com/ws");
ws.addEventListener("message", (e) => console.log(e.data));
ws.send("hello");
In Node 22+ WebSocket is built in. On older Node, use:
Server-Sent Events#
Lighter than WebSockets when the server only needs to push.
// server
res.writeHead(200, {
"content-type": "text/event-stream",
"cache-control": "no-cache",
"connection": "keep-alive",
});
res.write("data: hello\n\n");
// client
const es = new EventSource("/stream");
es.onmessage = (e) => console.log(e.data);
Higher-Level HTTP Clients#
DNS#
In Node.
import dns from "node:dns/promises";
const addrs = await dns.resolve4("example.com");
const ptr = await dns.reverse("8.8.8.8");
const srv = await dns.resolveSrv("_xmpp._tcp.example.com");
TLS / mTLS#
import https from "node:https";
const agent = new https.Agent({
ca: fs.readFileSync("ca.pem"),
cert: fs.readFileSync("client.pem"),
key: fs.readFileSync("client-key.pem"),
});
const res = await fetch("https://internal/", { dispatcher: undici_agent });
Servers / Frameworks#
For real applications, see Frameworks (Express, Fastify, Hono, Koa, NestJS). The standard library is fine for tiny services and prototypes; a framework saves work for everything else.
Pitfalls#
No default timeout on ``fetch``, always pair with an
AbortController.Headers are case-insensitive, but use lowercase to be safe.
``fetch`` doesn’t throw on 4xx / 5xx, check
res.okyourself.Reading a Response twice is an error,
clone()first if needed.Node TLS doesn’t use the system CA store on macOS / Windows by default, use
--use-system-ca(Node 22+) or setNODE_EXTRA_CA_CERTS.