cloudflare / cloudflare/workerd

Node.js Compat API Update Survey

Open
#6,924 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
8.7k
Forks
739
Avg merge
2d 20h
Merged PRs (30d)
174

Description

# Node.js Compat Gaps: workerd vs Node.js v22–v26

New APIs added to Node.js between v22.0.0 (April 2024) and v26.0.0 (May 2026)
that are missing or incomplete in workerd's `node:` module implementations.

(List needs to be reviewed to determine if the AI agent missed items or got items wrong)

## `node:crypto`

- ~~`crypto.hash()` — one-shot hash without creating a Hash stream (v22)~~ Implemented
- `KeyObject.prototype.toCryptoKey()` — convert Node.js KeyObject to WebCrypto CryptoKey (v23)
- `x509.validFromDate` / `x509.validToDate` — Date object accessors on X509Certificate (v23)
- `crypto.randomUUIDv7()` — time-sortable UUID v7 generation (v26)
- `crypto.argon2()` / `crypto.argon2Sync()` — Argon2 password hashing (v26)
- ML-KEM / ML-DSA post-quantum key encapsulation: `encapsulate()`, `decapsulate()` (v26)
- `x509.signatureAlgorithm` / `x509.signatureAlgorithmOid` (v26)
- Ed25519 context parameter support (v26)
- ~~`crypto.generateKey()` — noted as not yet implemented in workerd TS layer~~ Implemented?
- `crypto.diffieHellman()` async variant (v26)

## `node:webcrypto`

- KEM operations: `encapsulateBits()`, `encapsulateKey()`, `decapsulateBits()`, `decapsulateKey()` (v26)
- `SubtleCrypto.supports()` (v26)
- `subtle.getPublicKey()` (v26)
- Argon2 derivation params (v26)
- cSHAKE, KMAC, KangarooTwelve, TurboShake algorithms (v26)

## ~~`node:async_hooks`~~

- ~~`AsyncLocalStorage` constructor options: `{ defaultValue, name }` (v24)~~ Implemented in workerd already
- ~~`AsyncLocalStorage.enterWith()` — throws "not implemented" in workerd~~ Intentionally omitted
- ~~`AsyncLocalStorage.disable()` — throws "not implemented" in workerd~~ Intentionally omitted

## `node:assert`

- ~~`assert.partialDeepStrictEqual()` (v24)~~ Implemented
- `Class: Assert` — custom assert instances (v26)

## `node:path`

- `path.matchesGlob()` / `path.posix.matchesGlob()` / `path.win32.matchesGlob()` — code exists but throws "not implemented" (v23)

## `node:util`

- `util.parseArgs()` — throws "not implemented" in workerd (v22)
- ~~`util.styleText()` — terminal text styling, accepts array of formats (v22)~~
- ~~`util.types.isFloat16Array()` (v24)~~
- ~~`util.parseEnv()` — parse .env file format (v24)~~
- ~~`util.aborted()` — promise that resolves on AbortSignal abort (v22)~~
- `util.diff()` — diffing utility (v25)
- `util.transferableAbortController()` — throws "not implemented" in workerd
- `util.transferableAbortSignal()` — throws "not implemented" in workerd
- `util.getSystemErrorMap()` — throws "not implemented" in workerd
- `util.getSystemErrorName()` — throws "not implemented" in workerd
- `util.getSystemErrorMessage()` — throws "not implemented" in workerd
- ~~`util.isDeepStrictEqual()` options parameter (v25)~~

## `node:buffer`

- ~~`buffer.isAscii()` (v22)~~
- ~~`buffer.isUtf8()` (v22)~~
- `Buffer.copyBytesFrom()` (v22)
- `buffer.resolveObjectURL()` — noted as not implemented in workerd
- ~~`blob.bytes()` (v22)~~
- `blob.textStream()` (v25)
- Aligned allocations: `Buffer.allocUnsafe(size, alignment)` (v25)

## `node:zlib`

- ZIP archive API: `ZipBuffer`, `ZipEntry`, `ZipFile`, `createZipArchive()` (v25)
- Iterable compression helpers (v25)

## `node:fs`

- `fs.openAsBlob()` — noted as TODO in workerd (v22)
- `fsPromises.mkdtempDisposable()` (v25)
- `Class: Utf8Stream` (v25)
- `Class: StatFs` (v24)

## `node:sqlite`

- `DatabaseSync` full implementation — constructor is deleted in workerd, only constants exported (v22, stability 1.2)
- `StatementSync` full implementation — constructor is deleted in workerd (v22)
- `Session` (changeset support) (v24)
- `SQLTagStore` (tagged template SQL) (v25)
- `database.aggregate()` (v25)
- `database.setAuthorizer()` (v25)
- `database.serialize()` / `database.deserialize()` (v25)
- `sqlite.backup()` — throws in workerd (v25)
- `Symbol.dispose` support on DatabaseSync/StatementSync (v24)

## `node:diagnostics_channel`

- `TracingChannel` class — noted as TODO in workerd (v24)
- `BoundedChannel` / `BoundedChannelScope` (v25)
- `RunStoresScope` class (v25)
- Built-in channels for HTTP/net/DNS auto-instrumentation (v24)

## `node:dns`

- `dns.resolveTlsa()` — DANE/TLSA record resolution (v25)
- `Resolver.cancel()` — noted as not implemented in workerd

## `node:events`

- `events.addAbortListener()` (v22)
- `EventEmitterAsyncResource` (v22)

## `node:stream`

- `stream.isDestroyed()` / `stream.isErrored()` / `stream.isReadable()` / `stream.isWritable()` — static utility functions (v22)
- ~~`Readable.fromWeb()` / `Readable.toWeb()` (v22)~~
- ~~`Writable.fromWeb()` / `Writable.toWeb()` (v22)~~
- ~~`Duplex.fromWeb()` / `Duplex.toWeb()` (v22)~~

## `node:http`

- ~~`Class: WebSocket` — built-in WebSocket in http module (v22)~~
- `response.writeEarlyHints()` (v22)
- `response.writeInformation()` (v25)
- `message.signal` — AbortSignal on IncomingMessage (v24)
- `server[Symbol.asyncDispose]()` (v24)
- `closeAllConnections()` / `closeIdleConnections()` (v22)

## `node:https`

- `server[Symbol.asyncDispose]()` (v24)
- `closeAllConnections()` / `closeIdleConnections()` (v22)

## `node:net`

- `net/promises` API: `netPromises.connect()`, `netPromises.listen()` (v25)
- `Class: BoundSocket` (v25)
- `SocketAddress.parse()` (v24)
- `server[Symbol.asyncDispose]()` (v24)
- `server[Symbol.asyncIterator]()` (v25)
- `net.BlockList` improvements (release pending)

## `node:tls`

- `tls.setDefaultCACertificates()` (v25)
- `tls.getCACertificates()` (v25)
- `tls.getCertificateCompressionAlgorithms()` (v26)
- `tlsSocket.setKeyCert()` — throws "not implemented" in workerd
- `tlsSocket.exportKeyingMaterial()` — throws "not implemented" in workerd
- `tlsSocket.getPeerCertificate()` — throws "not implemented" in workerd
- `tlsSocket.getCertificate()` — throws "not implemented" in workerd
- `tlsSocket.getPeerX509Certificate()` — throws "not implemented" in workerd
- `tlsSocket.getX509Certificate()` — throws "not implemented" in workerd

## `node:dgram`

- `socket.bindSync()` / `socket.connectSync()` (v25)
- `socket[Symbol.asyncDispose]()` (v24)
- (entire module is a non-functional stub in workerd)

## `node:http2`

- `http2.performServerHandshake()` (v24)
- Extended CONNECT protocol support (v24)
- (entire module is a non-functional stub in workerd)

## `node:vm`

- `SourceTextModule` class — not implemented in workerd
- `SyntheticModule` class — not implemented in workerd
- `vm.constants.DONT_CONTEXTIFY` (v25)

## `node:module`

- `module.findPackageJSON()` (v25)
- `module.stripTypeScriptTypes()` (v25)
- `module.registerHooks()` — synchronous loader hooks (v25)
- `module.register()` — async loader hooks (v22, deprecated v26)
- `module.enableCompileCache()` / `module.flushCompileCache()` / `module.getCompileCacheDir()` (v23)
- `module.syncBuiltinESMExports()` — noted as "might support in the future" in workerd
- Source map support (`module.SourceMap`, `module.findSourceMap`) — noted in workerd as future

## `node:process`

- `process.loadEnvFile()` (v22)
- `process.finalization.register()` / `process.finalization.registerBeforeExit()` (v22)
- `process.permission.has()` / `process.permission.drop()` (v24)
- `process.availableMemory()` (v22)
- `process.constrainedMemory()` (v22)
- `process.execve()` (v25)
- `process.ref()` / `process.unref()` (v25)
- `process.threadCpuUsage()` (v25)
- `process.features.require_module` (v23)
- `process.features.typescript` (v25)

## `node:os`

- `os.availableParallelism()` (v22)
- `os.machine()` (v22)
- (module exists in workerd but all functions return hardcoded stub values)

## `node:perf_hooks`

- `PerformanceResourceTiming` (v22)
- `RecordableHistogram` (v22)
- `eventLoopUtilization()` — returns stub zeros in workerd
- `createHistogram()` — throws in workerd
- `monitorEventLoopDelay()` — throws in workerd
- Built-in Net/DNS/HTTP performance detail types (v24)
- `Histogram` API improvements (pending release)

## `node:console`

- globalThis.console is not Node.js-compatible (noted as TODO in workerd)

## `node:v8`

- `v8.queryObjects()` (v22)
- CPU profiling API (v25)
- `Serializer` / `Deserializer` — noted as "implement later" in workerd
- `writeHeapSnapshot()` — noted as "implement later" in workerd
- `setHeapSnapshotNearHeapLimit()` — noted as "implement later" in workerd
- (most functions are no-ops or throw in workerd)

## `node:test`

- `describe()` / `it()` / `test()` runner — not implemented in workerd (only MockTracker ported)
- `mock.module()` (v22)
- `mock.getter()` / `mock.setter()` / `mock.property()` (v24)
- `MockTimers` (v22)
- Snapshot testing (v22)
- `context.plan()` (v24)
- `context.waitFor()` (v25)
- `context.log()` (v25)
- `assert.register()` (v25)
- `getTestContext()` (v25)
- Test tags (v25)
- Global setup/teardown (v24)
- Coverage reporters (v24)
- OpenTelemetry integration (v25)

## `node:timers`

- `Symbol.dispose` support on `Timeout` / `Immediate` (v24)
- `timersPromises.scheduler.yield()` (v24)

## `node:wasi`

- Full WASI implementation — constructor throws in workerd (noted as "we might want to implement")

## `node:worker_threads`

- `BroadcastChannel` — constructor throws in workerd (noted as TODO: use globalThis.BroadcastChannel)

## Global Web Platform APIs (exposed by Node.js)

- ~~`EventSource` — Server-Sent Events client (v25)~~
- `navigator.locks` — Web Locks API (v25)
- `CloseEvent` global (v23)
- `ErrorEvent` global (v25)

## `Symbol.dispose` / `Symbol.asyncDispose` Support

Node.js v24+ added explicit resource management protocol support to these built-in objects.
workerd implementations of these objects do not currently support it:

- `net.Server`
- `http.Server`
- `https.Server`
- `Timeout`
- `Immediate`
- `dgram.Socket`
- `DatabaseSync`
- `StatementSync`
- `fsPromises.mkdtemp` (returns disposable)

## Deprecations Not Yet Reflected

Node.js deprecated or removed these APIs; workerd still exposes them without warnings:

- `crypto.createCipher()` / `crypto.createDecipher()` — EOL in v26
- `url.parse()` — runtime deprecated in v24
- `SlowBuffer` — EOL in v25
- `_stream_duplex`, `_stream_passthrough`, `_stream_readable`, `_stream_transform`, `_stream_writable` — removed in v26
- `_tls_common` / `_tls_wrap` — deprecated in v25
- `util.isArray()`, `util.isBoolean()`, `util.isNull()`, `util.isNumber()`, `util.isString()`, `util.isObject()`, `util.isFunction()`, `util.isError()`, `util.isDate()`, `util.isRegExp()`, `util.isUndefined()`, `util.isSymbol()`, `util.isPrimitive()`, `util.isNullOrUndefined()`, `util.isBuffer()`, `util.log()`, `util._extend()` — EOL in v23
- `zlib.bytesRead` — removed in v23
- `fs.F_OK` / `fs.R_OK` / `fs.W_OK` / `fs.X_OK` — removed in v25 (use `fs.constants.*`)
- `dirent.path` — removed in v24 (use `dirent.parentPath`)
- `assert.CallTracker` — EOL in v25
- `crypto.fips` — runtime deprecated in v23
- `punycode` module — deprecated since v7

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the listed Node.js v22–v26 APIs against the corresponding workerd node: module implementations and the entries marked implemented, TODO, or not implemented. Verify which gaps and version claims are accurate, then update the survey so each remaining item has a confirmed status and clear scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.