Target Node Version
22.x (derived from the @types/node 22.x validation baseline used by tests and type checks).
Support Tiers
| Tier | Label | Meaning |
|---|---|---|
| 1 | Bridge | Runtime implementation in secure-exec bridge modules. |
| 2 | Polyfill | Browser-compatible polyfill package implementation. |
| 3 | Stub | Minimal compatibility surface for lightweight usage and type/instance checks. |
| 4 | Deferred | require() succeeds, but APIs throw deterministic unsupported errors on call. |
| 5 | Unsupported | Not implemented by design; require() throws immediately. |
"<module>.<api> is not supported in sandbox".
Unsupported modules use: "<module> is not supported in sandbox".
Compatibility Matrix
| Module | Tier | Status |
|---|---|---|
fs | 1 (Bridge) + 4 (Deferred APIs) | Implemented: readFile, writeFile, appendFile, open, read, write, close, readdir, mkdir, rmdir, rm, unlink, stat, lstat, rename, copyFile, exists, createReadStream, createWriteStream, writev, access, realpath, chmod, chown, link, symlink, readlink, truncate, utimes, cp, mkdtemp, opendir, glob, statfs, readv, fdatasync, fsync. Metadata-sensitive operations (stat, exists, readdir with withFileTypes) use metadata-native driver paths instead of content probing. rename delegates to driver semantics (atomic where supported; explicit limitation errors where not). Deferred: watch, watchFile. |
process | 1 (Bridge) | Env access (permission-gated), cwd/chdir, exit semantics, timers, stdio, eventing, and basic usage/system metadata APIs. |
os | 1 (Bridge) | Platform/arch/version, user/system info, and os.constants. |
child_process | 1 (Bridge) + 5 (fork) | Implemented: spawn, spawnSync, exec, execSync, execFile, execFileSync; fork is intentionally unsupported. |
http | 1 (Bridge) | Implemented: request, get, createServer; bridged request/response/server classes and constants. Includes Agent with connection pooling (maxSockets, keepAlive), HTTP upgrade (101 Switching Protocols) handling, and trailer headers support. |
https | 1 (Bridge) | Implemented: request, get, createServer with the same contract as http, including Agent pooling, upgrade handling, and trailer headers. |
http2 | 3 (Stub) + 5 (Full support) | Provides compatibility classes (Http2ServerRequest, Http2ServerResponse); createServer and createSecureServer are unsupported. |
dns | 1 (Bridge) | Implemented: lookup, resolve, resolve4, resolve6, plus dns.promises variants. |
module | 1 (Bridge) | Implements createRequire, Module basics, and builtin resolution (require.resolve("fs") returns builtin identifiers). |
timers | 1 (Bridge) | setTimeout, clearTimeout, setInterval, clearInterval, setImmediate, clearImmediate. |
path | 2 (Polyfill) | path-browserify; supports default and named ESM imports. |
buffer | 2 (Polyfill) | Polyfill via buffer. |
url | 2 (Polyfill) | Polyfill via whatwg-url and node-stdlib-browser shims. |
events | 2 (Polyfill) | Polyfill via events. |
stream | 2 (Polyfill) | Polyfill via readable-stream. stream/web subpath supported (Web Streams API: ReadableStream, WritableStream, TransformStream, etc.). |
util | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
assert | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
querystring | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
string_decoder | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
zlib | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
vm | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
punycode | 2 (Polyfill) | Polyfill via node-stdlib-browser. |
crypto | 3 (Stub) | Limited bridge/polyfill blend; getRandomValues() and randomUUID() use host node:crypto secure randomness, or throw deterministic unsupported errors if host entropy is unavailable; subtle.* methods throw deterministic unsupported errors. |
tty | 2 (Polyfill) | tty-browserify; isatty() returns false; ReadStream/WriteStream are compatibility constructors. |
v8 | 3 (Stub) | Pre-registered stub with mock heap stats and JSON-based serialize/deserialize. |
constants | 2 (Polyfill) | constants-browserify; os.constants remains available via os. |
Fetch globals (fetch, Headers, Request, Response) | 1 (Bridge) | Bridged via network bridge implementation. |
async_hooks | 3 (Stub) | AsyncLocalStorage (with run, enterWith, getStore, disable, exit), AsyncResource (with runInAsyncScope, emitDestroy), createHook (returns enable/disable no-ops), executionAsyncId, triggerAsyncId. |
console | 1 (Bridge) | Circular-safe bounded formatting via bridge shim; log, warn, error, info, debug, dir, time/timeEnd/timeLog, assert, clear, count/countReset, group/groupEnd, table, trace. Drop-by-default; consumers use onStdio hook for streaming. |
diagnostics_channel | 3 (Stub) | No-op channel(), tracingChannel(), Channel constructor; channels always report hasSubscribers: false; publish, subscribe, unsubscribe are no-ops. Provides Fastify compatibility. |
Deferred modules (net, tls, readline, perf_hooks, worker_threads) | 4 (Deferred) | require() returns stubs; APIs throw deterministic unsupported errors when called. |
Unsupported modules (dgram, cluster, wasi, inspector, repl, trace_events, domain) | 5 (Unsupported) | require() fails immediately with deterministic unsupported-module errors. |
Tested Packages
The project-matrix test suite validates that real-world npm packages produce identical output in secure-exec and host Node.js. Each fixture is a black-box Node project with no sandbox-specific code.| Package | Category | What It Tests |
|---|---|---|
| express | Web Framework | HTTP server, middleware, routing |
| fastify | Web Framework | Async middleware, schema validation, plugins |
| next | Web Framework | React SSR, module resolution, build tooling |
| vite | Build Tool | ESM, HMR server, plugin system |
| astro | Web Framework | Island architecture, SSR, multi-framework |
| hono | Web Framework | ESM imports, lightweight HTTP |
| axios | HTTP Client | HTTP client requests via fetch adapter, JSON APIs |
| node-fetch | HTTP Client | Fetch polyfill using http module, stream piping |
| dotenv | Configuration | Environment variable loading, fs reads |
| semver | Utility | Version parsing and comparison |
| ssh2 | Networking | SSH client/server, crypto, streams, events |
| ssh2-sftp-client | Networking | SFTP client, file transfer APIs over SSH |
| pg | Database | PostgreSQL client, Pool/Client classes, type parsers |
| mysql2 | Database | MySQL client, connection/pool classes, escape/format utilities |
| ioredis | Database | Redis client, Cluster, Command, pipeline/multi transaction APIs |
| drizzle-orm | Database | ORM schema definition, query building, ESM module graph |
| ws | Networking | WebSocket client/server, HTTP upgrade, events |
| jsonwebtoken | Crypto | JWT signing (HS256), verification, decode |
| bcryptjs | Crypto | Pure JS password hashing and verification |
| chalk | Terminal | Terminal string styling, ANSI escape codes |
| lodash-es | Utility | Large ESM module resolution at scale |
| pino | Logging | Structured JSON logging, child loggers, serializers |
| uuid | Crypto | UUID generation (v4, v5), validation, version detection |
| yaml | Utility | YAML parsing, stringifying, document API |
| zod | Validation | Schema definition, parsing, safe parse, transforms |
| rivetkit | SDK | Local vendor package resolution |
| crypto (builtin) | Crypto | crypto.randomBytes, randomUUID, getRandomValues |
| fs-metadata-rename | Filesystem | stat metadata, rename semantics |
| module-access | Module Resolution | Node modules overlay access |
| conditional-exports | Module Resolution | Package exports field resolution |
| optional-deps | Module Resolution | Optional dependency handling |
| peer-deps | Module Resolution | Peer dependency resolution |
| transitive-deps | Module Resolution | Transitive dependency chains |
| pnpm-layout | Package Manager | pnpm node_modules structure |
| npm-layout | Package Manager | npm flat node_modules layout |
| yarn-classic-layout | Package Manager | Yarn v1 node_modules layout |
| yarn-berry-layout | Package Manager | Yarn Berry PnP/node_modules layout |
| bun-layout | Package Manager | Bun node_modules layout |
| workspace-layout | Package Manager | npm workspace node_modules layout |
| sse-streaming | Networking | SSE server, chunked transfer-encoding, streaming reads |
| net-unsupported (fail) | Error Handling | net.createServer correctly errors |
Known Unsupported npm Packages (Native Extensions)
These popular packages ship native binaries or platform-specific.node addons and cannot run inside a secure-exec V8 isolate. Native addons require Node’s native module loader (dlopen), which is not available in the sandbox. The overlay module loader explicitly rejects .node files.
| Package | Weekly Downloads | Why It Fails | Pure-JS Alternative |
|---|---|---|---|
| esbuild | 116M | Spawns a platform-specific Go binary; JS API is a thin IPC wrapper | esbuild-wasm (same API, ~3x slower) |
| rollup (v4+) | 78M | Rust parser via napi-rs (@rollup/rollup-linux-x64-gnu, etc.) | @rollup/wasm-node (WASM fallback) |
| vite | 65M | Hard dependency on esbuild (dep optimization) and rollup (bundling) | webpack (pure JS) |
| tailwindcss (v4) | 51M | Rust Oxide engine via napi-rs (@tailwindcss/oxide-*) | tailwindcss@3 (pure JS PostCSS plugin) |
| next | 27M | Rust SWC compiler (@next/swc-*); also depends on esbuild | No pure-JS equivalent |
| sass-embedded | — | Wraps a native Dart executable | sass (dart2js compiled, pure JS) |
| node-sass | — | C++ LibSass binding via node-gyp (deprecated) | sass |
| bcrypt | — | C++ binding via node-gyp | bcryptjs (pure JS) |
| @swc/core | — | Rust/napi-rs transpiler | typescript transpileModule() or babel |
| sharp | — | C++ libvips binding via prebuild | jimp (pure JS, slower) |
| better-sqlite3 | — | C++ SQLite binding via node-gyp | sql.js (WASM-based SQLite) |
| canvas | — | C++ Cairo/Pango binding via node-gyp | @napi-rs/canvas is also native; no pure-JS equivalent |
next, vite) have fixtures that test module resolution and limited API surface, not the full native build pipeline.
Logging Behavior
console.log/warn/errorare supported and serialize arguments with circular-safe bounded formatting.exec()/run()results do not expose bufferedstdout/stderrfields.- By default, secure-exec drops console emissions instead of buffering runtime-managed output.
- Consumers that need logs should use the explicit
onStdiohook to streamstdout/stderrevents in emission order.
TypeScript Workflows
- Core
secure-execruntimes execute JavaScript only. - Sandboxed TypeScript type checking and compilation belong in the separate
@secure-exec/typescriptpackage.
Node-Modules Overlay Behavior
- Node runtime composes a read-only
/app/node_modulesoverlay from<cwd>/node_modules(defaultcwdis hostprocess.cwd(), configurable viamoduleAccess.cwd). - Overlay reads are constrained to canonical paths under
<cwd>/node_modulesand fail closed on out-of-scope symlink/canonical escapes. - Writes and mutations under
/app/node_modules/**are denied withEACCES. - Native addons (
.node) are rejected in overlay-backed module loading.
Permission Model (Runtime/Bridge Scope)
- This section describes the core runtime/bridge contract only.
- Runtime permissions are deny-by-default for
fs,network,childProcess, andenv. - If a domain checker is not configured, operations fail with
EACCES. filterEnvstrips environment variables unlesspermissions.envexplicitly allows them.- Embedders can opt in via explicit permission policies such as
allowAll,allowAllFs,allowAllNetwork,allowAllChildProcess, andallowAllEnv. - Driver-specific convenience defaults (for example, direct
createNodeDriver(...)usage when adapters are provided without an explicitpermissionspolicy) are implementation details and are not the canonical runtime/bridge security contract.