AphrodyBun GitHub

Runtime docs ยท Runtime ยท Standards & Compatibility

Node.js Compatibility

Bun's compatibility status with Node.js APIs, modules, and globals

Every day, Bun gets closer to 100% Node.js API compatibility. Popular frameworks like Next.js, Express, and millions of npm packages intended for Node.js work with Bun. To ensure compatibility, we run thousands of tests from Node.js' test suite before every release of Bun.

If a package works in Node.js but doesn't work in Bun, we consider it a bug in Bun. Open an issue and we'll fix it.

We update this page regularly. It reflects the latest version of Bun's compatibility with Node.js v26.

Built-in Node.js modules

node:assert

๐ŸŸข Fully implemented. Legacy-mode deepEqual uses Bun.deepEquals semantics rather than Node's loose == comparison, and function-valued or printf-style message arguments are not formatted.

node:buffer

๐ŸŸข Fully implemented. A single Buffer is capped at 4 GiB (buffer.constants.MAX_LENGTH is 2**32).

node:console

๐ŸŸข Fully implemented. Bun writes console output directly to the stdout/stderr file descriptors and formats it with its own inspector. As a result, replacing process.stdout.write does not capture the output, and object layout differs from util.inspect. console.trace() writes to stdout and console.time*() to stderr.

node:dgram

๐ŸŸข Fully implemented. 99% of Node.js's test suite passes. addMembership() does not implicitly bind an unbound socket; call bind() first.

node:diagnostics_channel

๐ŸŸก channel(), subscribe(), tracingChannel() and the http client, http2 and dgram built-in channels are implemented. Missing boundedChannel() and the http.server.*, net, module, console, child_process and worker_threads built-in channels. Subscribers do not keep a Channel alive, so hold a reference to it.

node:dns

๐ŸŸข Fully implemented. Missing resolveTlsa. Bun ignores the Resolver maxTimeout option.

node:events

๐ŸŸข Fully implemented. 95% of Node.js's test suite passes. EventEmitterAsyncResource uses AsyncResource underneath, so its asyncId is always 0.

node:fs

๐ŸŸข Fully implemented. 98% of Node.js's test suite passes. Stats objects lack the Temporal.Instant getters (atimeInstant and friends).

node:http

๐ŸŸข Fully implemented. http.Server does not extend net.Server. Bun ignores listen(handle) and the fd, ipv6Only and signal options of listen(). keepAlive/keepAliveInitialDelay on the server are no-ops.

node:https

๐ŸŸก request, get, Agent and globalAgent are implemented, including connection pooling. Client sockets are tls.TLSSockets. https.Server is http.Server with TLS options rather than a tls.Server. Its request sockets (req.socket) are not tls.TLSSockets: encrypted, authorized and servername work, but getPeerCertificate() and getCipher() are missing. setSecureContext(), addContext(), SNICallback and handshakeTimeout are not supported.

node:os

๐ŸŸข Fully implemented. userInfo() reads username, shell and homedir from the environment (USER, SHELL, HOME) rather than the passwd database. machine() returns "arm64" instead of "aarch64" on Linux arm64.

node:path

๐ŸŸข Fully implemented. matchesGlob() uses Bun.Glob semantics rather than minimatch (* matches dotfiles, no extglobs). path.win32 differs from Node in a few edge cases involving device paths and reserved names.

node:punycode

๐ŸŸข Fully implemented. 100% of Node.js's test suite passes. Deprecated by Node.js.

node:querystring

๐ŸŸข Fully implemented. 100% of Node.js's test suite passes.

node:readline

๐ŸŸข Fully implemented.

node:stream

๐ŸŸข Fully implemented. isReadable, isWritable, isErrored and Readable.isDisturbed only understand Node.js streams, not web streams.

node:string_decoder

๐ŸŸข Fully implemented. 100% of Node.js's test suite passes. end() does not accept a string argument.

node:timers

๐ŸŸข Fully implemented. The exports are the same functions as the globals. node:timers/promises (including scheduler.wait() and scheduler.yield()) is also implemented.

node:tty

๐ŸŸข Fully implemented. ReadStream and WriteStream extend the fs streams rather than net.Socket, and constructing them on a non-TTY fd returns a stream with isTTY set to false instead of throwing.

node:url

๐ŸŸข Fully implemented.

node:zlib

๐ŸŸข Fully implemented. 98% of Node.js's test suite passes.

node:async_hooks

๐ŸŸก AsyncLocalStorage and AsyncResource are implemented. createHook, executionAsyncId, triggerAsyncId and executionAsyncResource are stubs: Bun does not invoke hooks, apart from init for process.nextTick, and async ids are always 0. Node.js strongly discourages these APIs in favor of AsyncLocalStorage. Bun does not propagate AsyncLocalStorage context into MessagePort, BroadcastChannel or Worker events.

node:child_process

๐ŸŸก IPC can send net.Socket, net.Server and dgram.Socket handles (including to and from Node.js processes), but not http server sockets. serialization: "advanced" only works between Bun processes, so use JSON serialization for Node.js โ†” Bun IPC. Missing subprocess.channel.ref()/unref(). You cannot pass a child's stdout/stderr as another child's stdio, and spawnSync does not return extra stdio pipes in output.

node:cluster

๐ŸŸก net and dgram servers in workers are shared through the primary as in Node.js (SCHED_RR and SCHED_NONE), and handles can be passed with worker.send(). node:http/node:https servers in workers each bind their own socket instead, so load-balancing HTTP requests across processes is only supported on Linux (through SO_REUSEPORT). Otherwise, implemented but not battle-tested.

node:crypto

๐ŸŸก Missing encapsulate/decapsulate (you can use ML-KEM keys through crypto.subtle). argon2() and argon2Sync() are implemented. Custom engines (setEngine()) throw, setFips() is a no-op and secureHeapUsed() returns undefined. Bun's crypto is backed by BoringSSL, which lacks the ed448, x448, rsa-pss, dsa, dh and ml-kem-512 key types, EC curves other than P-224/256/384/521 (no secp256k1), and the CCM, OCB, XTS and chacha20-poly1305 ciphers. The DiffieHellman class (createDiffieHellman(), getDiffieHellman()) works.

node:domain

๐ŸŸก Missing Domain members. A domain only catches errors thrown synchronously inside run()/bind() or emitted by emitters passed to add(). Bun does not route errors from timers, process.nextTick, promises and other async callbacks to the domain.

node:http2

๐ŸŸข Client & server are implemented. 94% of Node.js's test suite passes. The maxDeflateDynamicTableSize, peerMaxConcurrentStreams and streamResetBurst/streamResetRate options are accepted but ignored.

node:module

๐ŸŸก Missing Module#load(), registerHooks, findPackageJSON, stripTypeScriptTypes, getSourceMapsSupport/setSourceMapsSupport. Overriding require.cache, require.extensions and module._resolveFilename is supported. syncBuiltinESMExports, module._load, module._pathCache and module.register are no-ops (we recommend Bun.plugin instead). findSourceMap always returns undefined.

node:net

๐ŸŸข Fully implemented, including BlockList, SocketAddress, autoSelectFamily, Unix domain sockets and server.listen({ fd }). new net.Socket({ fd }) cannot read from an existing file descriptor (only write-only wrapping works). server.listen(handle) only accepts { fd }. Missing blockList.toJSON()/fromJSON().

node:perf_hooks

๐ŸŸก monitorEventLoopDelay(), createHistogram(), timerify() and PerformanceObserver (mark, measure, function, net, http and http2 entries) are implemented. Bun never emits gc, dns or resource entries. eventLoopUtilization() always returns zeros, and performance.nodeTiming holds placeholder values. The Node-specific additions to the global performance object only appear once node:perf_hooks has been imported.

node:process

๐ŸŸก See process Global.

node:sys

๐ŸŸข See node:util.

node:tls

๐ŸŸก Missing pskCallback, OCSP stapling (requestOCSP), the server 'newSession'/'resumeSession' events and session ticket keys (ticketKeys is ignored). As a result, session resumption does not work across processes. Bun uses BoringSSL, so tlsSocket.renegotiate() always fails and getEphemeralKeyInfo()/getSharedSigalgs() return no information.

node:util

๐ŸŸข Fully implemented. Missing diff (experimental in Node.js), transferableAbortSignal and transferableAbortController. debuglog() ignores its callback argument and the returned function has no enabled property.

node:v8

๐ŸŸก writeHeapSnapshot, getHeapSnapshot, getHeapStatistics, getHeapSpaceStatistics, GCProfiler and startupSnapshot are implemented. The heap statistics describe JavaScriptCore's single heap, and setFlagsFromString ignores the flags it is given. serialize and deserialize use JavaScriptCore's wire format instead of V8's. Missing queryObjects, startCpuProfile, startHeapProfile, Serializer/Deserializer, takeCoverage/stopCoverage and promiseHooks. For profiling, use bun:jsc instead.

node:vm

๐ŸŸข Fully implemented, including vm.Script, vm.createContext, vm.runInContext, vm.runInNewContext, vm.runInThisContext, vm.compileFunction, vm.isContext, the ES module classes vm.Module, vm.SourceTextModule and vm.SyntheticModule (exported without --experimental-vm-modules), and importModuleDynamically support. The timeout, breakOnSigint, cachedData, microtaskMode and codeGeneration options are supported. An importModuleDynamically callback that returns a promise for a vm.Module resolves import() to the module object rather than its namespace. vm.measureMemory() reports whole-heap figures for every context.

node:wasi

๐ŸŸก Partially implemented. WASI supports args, env, preopens, wasiImport and start(), and bun ./program.wasm runs a WASI command directly. Missing getImportObject() (use wasiImport), initialize() and the sock_accept import. Bun ignores the version, returnOnExit, stdin, stdout and stderr options, so proc_exit exits the Bun process.

node:worker_threads

๐ŸŸก Worker ignores the resourceLimits and trackUnmanagedFds options. Some execArgv flags take effect in the worker, for example --no-addons, --stack-trace-limit and --tls-min-v1.3. Others, for example --conditions and --no-deprecation, only set process.execArgv. worker.performance.eventLoopUtilization() is a stub. Missing moveMessagePortToContext and locks.

node:inspector

๐ŸŸก Partially implemented. Session supports the Profiler domain (including precise coverage), Runtime.enable and NodeTracing, from both node:inspector and node:inspector/promises. After open(), Session also forwards Debugger configuration commands such as Debugger.enable and Debugger.setBreakpointByUrl to the inspector server. Their results, such as breakpointId, are not returned. Other Session commands such as Runtime.evaluate and the HeapProfiler domain are not implemented. open(), url(), close() and waitForDebugger() are implemented. open() serves the Debugger and Runtime domains and throws in workers. Missing Network.

node:repl

๐ŸŸก Mostly implemented. bun --interactive starts a Node.js-compatible REPL. The REPL does not show result previews (they need V8's inspector-based side-effect-free eval). Tab-completion skips let/const/class bindings, and some V8-specific error-message and stack-frame wording differs.

node:sqlite

๐ŸŸข Fully implemented. backup() runs synchronously and blocks the event loop for the duration of the copy (Node runs it on a worker thread). A Buffer/Uint8Array database path must be valid UTF-8 (Node passes the raw bytes through; Bun rejects non-UTF-8 with ERR_INVALID_ARG_VALUE). On macOS, Bun uses the system libsqlite3.dylib. loadExtension() requires a full SQLite build, and so do createSession()/applyChangeset() on older macOS releases. To use a full SQLite build, call require("bun:sqlite").Database.setCustomSQLite(path) before opening a database.

node:test

๐ŸŸก Partially implemented. The in-process API works when test files run under bun test: tests, suites, subtests, hooks, t.plan(), t.assert, assert.register(), t.waitFor(), getTestContext(), expectFailure, and t.mock (function/method/getter/setter/property mocks and mock timers). run() requires an explicit files list and runs each file in a bun test child process. Most of its options (globPatterns, watch, coverage, shard, only, testNamePatterns, ...) throw ERR_NOT_IMPLEMENTED. Missing node:test/reporters, snapshot testing, mock.module(), t.runOnly(), code coverage, --test-only, test-level signal abort, and Node's --test CLI runner mode. test.only() / {only: true} are accepted but do not filter. concurrency is validated but subtests always run serially. Use bun:test instead.

node:trace_events

๐ŸŸข Fully implemented. createTracing(), getEnabledCategories() and the --trace-events-enabled, --trace-event-categories and --trace-event-file-pattern flags are supported. Bun writes the trace at exit. Some categories record less than in Node.js. For example, node.async_hooks only records timers, and the v8 category is a placeholder, since JavaScriptCore has no V8 GC or compile events.

node:quic

๐ŸŸข Implemented: listen(), connect(), QuicEndpoint, QuicSession and QuicStream. 99% of Node.js's test suite passes. The API is experimental in Node.js, and importing it emits an ExperimentalWarning in Bun too.

node:sea

๐Ÿ”ด Not implemented. Use bun build --compile to build single-file executables instead.

Node.js globals

The following list covers the globals implemented by Node.js and Bun's compatibility status for each.

AbortController

๐ŸŸข Fully implemented.

AbortSignal

๐ŸŸข Fully implemented.

Blob

๐ŸŸข Fully implemented. The endings constructor option is ignored, and blob.stream() does not support BYOB readers.

Buffer

๐ŸŸข Fully implemented. A single Buffer is capped at 4 GiB (buffer.constants.MAX_LENGTH is 2**32).

ByteLengthQueuingStrategy

๐ŸŸข Fully implemented.

__dirname

๐ŸŸข Fully implemented.

__filename

๐ŸŸข Fully implemented.

atob()

๐ŸŸข Fully implemented.

Atomics

๐ŸŸข Fully implemented.

BroadcastChannel

๐ŸŸข Fully implemented.

btoa()

๐ŸŸข Fully implemented.

clearImmediate()

๐ŸŸข Fully implemented.

clearInterval()

๐ŸŸข Fully implemented.

clearTimeout()

๐ŸŸข Fully implemented.

CloseEvent

๐ŸŸข Fully implemented.

CompressionStream

๐ŸŸข Fully implemented.

console

๐ŸŸข Fully implemented. See node:console for the differences in how output is written.

CountQueuingStrategy

๐ŸŸข Fully implemented.

Crypto

๐ŸŸข Fully implemented.

SubtleCrypto (crypto)

๐ŸŸข Fully implemented. See SubtleCrypto for the algorithms Bun does not support.

CryptoKey

๐ŸŸข Fully implemented.

CustomEvent

๐ŸŸข Fully implemented.

DecompressionStream

๐ŸŸข Fully implemented.

ErrorEvent

๐ŸŸข Fully implemented.

Event

๐ŸŸข Fully implemented.

EventTarget

๐ŸŸข Fully implemented.

exports

๐ŸŸข Fully implemented.

fetch

๐ŸŸข Fully implemented. The integrity option is ignored.

File

๐ŸŸข Fully implemented. File objects report Blob as their constructor and Symbol.toStringTag.

FormData

๐ŸŸข Fully implemented. As in Node.js and browsers, FormData has no toJSON() method, so JSON.stringify(formData) returns "{}". Use Object.fromEntries(formData) or [...formData] to serialize the entries.

global

๐ŸŸข Implemented. global is an object containing all objects in the global namespace. It's rarely referenced directly, as its contents are available without a prefix, for example console instead of global.console.

globalThis

๐ŸŸข Aliases to global.

Headers

๐ŸŸข Fully implemented.

MessageChannel

๐ŸŸข Fully implemented.

MessageEvent

๐ŸŸข Fully implemented.

MessagePort

๐ŸŸข Fully implemented. The EventEmitter-style methods Node.js adds (on(), once(), off(), ...) are only installed once node:worker_threads has been loaded.

module

๐ŸŸข Fully implemented. Missing module.isPreloading.

๐ŸŸก userAgent, platform and hardwareConcurrency are implemented. Missing language, languages and locks. The Navigator class is not a global.

PerformanceEntry

๐ŸŸข Fully implemented.

PerformanceMark

๐ŸŸข Fully implemented.

PerformanceMeasure

๐ŸŸข Fully implemented.

PerformanceObserver

๐ŸŸก Observing mark and measure entries works. Bun only delivers Node-only entry types (function, http, net, ...) to the node:perf_hooks PerformanceObserver, and never emits gc, dns or resource entries.

PerformanceObserverEntryList

๐ŸŸข Fully implemented.

PerformanceResourceTiming

๐ŸŸก The class exists, but no entries are ever created: fetch() does not record resource timing and performance.markResourceTiming() is a no-op.

performance

๐ŸŸก now(), timeOrigin, mark(), measure() and getEntries() are implemented. The Node.js additions (eventLoopUtilization(), nodeTiming, timerify()) only exist once node:perf_hooks has been loaded. eventLoopUtilization() always returns zeros and nodeTiming holds placeholder values.

process

๐ŸŸก Mostly implemented. process.binding (internal Node.js bindings some packages rely on) is partially implemented: buffer, config, constants, crypto/x509, fs, http_parser, natives, tty_wrap, util and uv are available, the rest throw. Setting process.title is a no-op on macOS & Linux. getActiveResourcesInfo(), _getActiveHandles() and _getActiveRequests() always return an empty array, setSourceMapsEnabled() is a no-op, and process.report.writeReport() writes nothing. Missing sourceMapsEnabled and addUncaughtExceptionCaptureCallback.

queueMicrotask()

๐ŸŸข Fully implemented.

QuotaExceededError

๐Ÿ”ด Not implemented.

ReadableByteStreamController

๐ŸŸข Fully implemented.

ReadableStream

๐ŸŸข Fully implemented. Streams cannot be transferred with postMessage() or structuredClone().

ReadableStreamBYOBReader

๐ŸŸข Fully implemented.

ReadableStreamBYOBRequest

๐ŸŸข Fully implemented.

ReadableStreamDefaultController

๐ŸŸข Fully implemented.

ReadableStreamDefaultReader

๐ŸŸข Fully implemented.

require()

๐ŸŸข Fully implemented, including require.main, require.cache, require.resolve.

Response

๐ŸŸข Fully implemented. A Response constructed from a string does not expose the default content-type header in headers (Bun.serve() still sends it).

Request

๐ŸŸก Missing keepalive and duplex. The credentials, integrity, referrer and referrerPolicy options are accepted but ignored.

setImmediate()

๐ŸŸข Fully implemented.

setInterval()

๐ŸŸข Fully implemented.

setTimeout()

๐ŸŸข Fully implemented.

structuredClone()

๐ŸŸข Fully implemented. Only ArrayBuffer and MessagePort can be transferred, and cloned Errors lose their cause.

Storage

๐Ÿ”ด Not implemented. Bun has no Storage, localStorage or sessionStorage globals.

SubtleCrypto

๐ŸŸข Fully implemented, including supports(), getPublicKey(), the encapsulate*()/decapsulate*() methods, ML-DSA, ML-KEM-768/ML-KEM-1024, SHA3-* and ChaCha20-Poly1305. Missing the Ed448, X448, AES-OCB, Argon2*, cSHAKE*, KMAC*, KT128/KT256, TurboSHAKE* and ML-KEM-512 algorithms (all experimental in Node.js).

DOMException

๐ŸŸข Fully implemented. Instances are not native errors (Error.isError() returns false).

TextDecoder

๐ŸŸข Fully implemented.

TextDecoderStream

๐ŸŸข Fully implemented.

TextEncoder

๐ŸŸข Fully implemented.

TextEncoderStream

๐ŸŸข Fully implemented.

TransformStream

๐ŸŸข Fully implemented. Cannot be transferred with postMessage() or structuredClone().

TransformStreamDefaultController

๐ŸŸข Fully implemented.

URL

๐ŸŸข Fully implemented.

URLPattern

๐ŸŸข Fully implemented.

URLSearchParams

๐ŸŸข Fully implemented.

WebAssembly

๐ŸŸข Fully implemented. Memory64 is disabled by default (set BUN_JSC_useWasmMemory64=1 to enable it).

WebSocket

๐ŸŸข Fully implemented. binaryType defaults to "nodebuffer", so binary messages arrive as Buffers. Node.js defaults to "blob".

WritableStream

๐ŸŸข Fully implemented. Cannot be transferred with postMessage() or structuredClone().

WritableStreamDefaultController

๐ŸŸข Fully implemented.

WritableStreamDefaultWriter

๐ŸŸข Fully implemented.