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.
navigator
๐ก 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.