This document describes how Deno implements Node.js network and HTTP compatibility through polyfills. It covers the node:net, node:http, node:https, node:http2, node:tls, node:dns, and node:dgram modules, explaining how they bridge Node.js APIs to Deno's native networking capabilities and Rust-based operations.
Node.js networking polyfills in Deno translate Node.js-style APIs into Deno's native networking primitives. The implementation strategy varies by module:
| Module | Strategy | Primary Bridge |
|---|---|---|
node:http | Wraps hyper HTTP/1.1 client | op_node_http_request_with_conn |
node:https | Extends node:http with TLS | Deno's TLS ops + HTTP polyfill |
node:http2 | Wraps nghttp2 via libnghttp2 | op_http2_connect, BindingHttp2Session |
node:net | Wraps Deno's TCP primitives | TCP handle from tcp_wrap.ts |
node:tls | Wraps Deno's TLS primitives | TLSWrap in tls_wrap.rs |
node:dns | Wraps c-ares library | op_node_getaddrinfo, cares_wrap.ts |
node:dgram | Wraps Deno's UDP primitives | UDP handle from udp_wrap.ts |
Sources: ext/node/polyfills/http.ts8-25 ext/node/polyfills/net.ts96-101 ext/node/polyfills/https.ts68-80 ext/node/polyfills/internal_binding/cares_wrap.ts58-64 ext/node/ops/tls_wrap.rs12-26
The node:http polyfill is built on several internal modules that mirror Node.js internal structure. ClientRequest manages outgoing requests, while Server handles incoming connections.
Figure 1: HTTP Module Architecture
Sources: ext/node/polyfills/http.ts8-25 ext/node/polyfills/http.ts62-64 ext/node/polyfills/_http_server.js59-83
node:https extends node:http by using node:tls to wrap connections. It sets default ALPN protocols to ["http/1.1"] and utilizes tls.Server as the base class for https.Server ext/node/polyfills/https.ts90-110
Sources: ext/node/polyfills/https.ts106-132 ext/node/polyfills/https.ts220-223
The node:net module provides TCP socket functionality through the Socket class. It uses TCP and Pipe handles which are thin wrappers around Deno's underlying resources, managed via AsyncWrap.
Figure 2: Net Module Resource Mapping
Sources: ext/node/polyfills/net.ts96-107 ext/node/polyfills/internal_binding/stream_wrap.ts60-82 ext/node/polyfills/net.ts199-211
To ensure AsyncLocalStorage and async_hooks work correctly across native libuv-style callbacks, Deno captures an async context snapshot (kAsyncContext) when a connection is initiated and restores it before invoking the completion callback ext/node/polyfills/net.ts188-211
The node:tls implementation relies on TLSWrap, a stream interceptor that sits between JavaScript and an underlying transport stream (like a TCP socket).
Data Flow in TLSWrap:
rustls writer ext/node/ops/tls_wrap.rs21rustls → Written to underlying stream ext/node/ops/tls_wrap.rs23rustls ext/node/ops/tls_wrap.rs24rustls → Emitted to JS ext/node/ops/tls_wrap.rs22Sources: ext/node/ops/tls_wrap.rs12-26 ext/node/polyfills/_tls_wrap.js112-117
Deno implements the node:dns module by bridging to Rust ops that perform name resolution. A critical security feature is the kPermTokenSink symbol, which ensures that internal network permission tokens used by net.connect do not escape to user-supplied callbacks ext/node/polyfills/internal_binding/cares_wrap.ts96-102
Key Functions:
getaddrinfo: Uses op_node_getaddrinfo and supports IP family filtering (IPv4/IPv6) ext/node/polyfills/internal_binding/cares_wrap.ts127-202getnameinfo: Uses op_node_getnameinfo for reverse lookups ext/node/polyfills/internal_binding/cares_wrap.ts229-236Sources: ext/node/polyfills/internal_binding/cares_wrap.ts58-64 ext/node/polyfills/internal_binding/cares_wrap.ts143-153
The node:dgram module is implemented via UDP and UDPConnectWrap bindings. These bridge to Deno's native UDP capabilities, supporting features like membership management for multicast and socket binding to specific interfaces.
Sources: ext/node/polyfills/internal_binding/udp_wrap.ts1-50