Module A-20·11 min read

Native fetch socket pool mechanics, Web Crypto vs libuv thread pool, and profiling ReadableStream memory leaks under RPC load.

Module 19 — The Modern Web Standard Shift: Undici, fetch, and Web Crypto

What this module covers: Node.js 18 shipped native fetch — built on Undici, a from-scratch HTTP/1.1 and HTTP/2 client that replaced the legacy http.request internals. The connection pool model changed. Garbage collection behavior changed. Performance characteristics changed. Engineers who understand http.request semantics may be surprised by subtle differences in how fetch handles keep-alive, connection reuse, and stream consumption. This module covers Undici's architecture, how to avoid ReadableStream memory leaks when consuming large RPC responses, and the Web Crypto API as a replacement for libuv thread-pool-dependent cryptographic operations.


Undici: The New HTTP Client Foundation

undici is the HTTP client library underlying Node.js's native fetch. It was written from scratch (unlike the legacy http module which dates to 2009) with modern HTTP semantics, connection pooling, and proper backpressure.

Connection Pool Architecture

Unlike http.request which uses a per-hostname keep-alive agent, Undici uses a Pool or Client with configurable connection counts:

javascript

ReadableStream Memory Leaks: The Critical Mistake

Every fetch response (and Undici response) has a body that is a ReadableStream. If you don't consume the body, the connection is not released back to the pool:

javascript
javascript

Large Response Streaming

For blockchain RPC responses that return multi-MB block data, streaming avoids loading the entire response into memory:

javascript

Performance Profiling: fetch vs http.request

javascript

For maximum throughput between internal services: use undici.Pool directly instead of fetch. The fetch API adds overhead for cross-browser compatibility. Pool.request exposes Undici's full performance.


Web Crypto API: Thread-Pool-Free Cryptography

Node.js's crypto module routes expensive operations (PBKDF2, scrypt, key derivation) through the libuv thread pool. The Web Crypto API (globalThis.crypto.subtle) offers the same operations but implemented differently — some operations run synchronously in V8 without thread pool involvement.

Replacing Thread-Pool Operations

javascript

Fast Web Crypto Operations (No Thread Pool)

javascript

Impact on libuv Thread Pool

javascript

Summary

ConceptKey Takeaway
UndiciUnderlying fetch in Node.js 18+. Modern connection pool. Better throughput than legacy http.
Pool.requestDirect Undici API, 71% faster than fetch. Use for inter-service HTTP at high throughput.
Body consumptionAlways consume the response body. Unconsumed bodies hold connections in the pool forever.
response.body.cancel()Explicitly release the connection without reading the body. Use in error paths.
Web Crypto vs cryptoWeb Crypto uses standard API. HMAC, SHA, AES operations often faster than callback-based legacy API.
Sync crypto.createHashFor hot paths: synchronous SHA-256 via crypto.createHash is fastest. No await overhead.
crypto.randomUUID()Synchronous, Web Standards, no thread pool. Best for request ID generation.

Knowledge Check

When using Node.js's native fetch (built on Undici), what is a critical consequence of failing to consume the response body (e.g., throwing an error before reading response.json() or response.text())?


For maximum possible HTTP throughput when making internal service-to-service calls, which approach provides the best performance in modern Node.js?


When performing cryptographic operations at very high throughput (e.g., 50,000 tx/sec), what is the main advantage of using crypto.createHash('sha256') over asynchronous APIs like crypto.pbkdf2?

Test your knowledge with more question sets

Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.