Elide for Deno users

What works unchanged, which commands and permission flags change, and how Elide compares with Deno.

Elide runs TypeScript, Web APIs, node:* modules and npm packages; the Deno global is absent.

Run the same code

elide app.ts                    # or: elide run app.ts
elide install --ecosystems=npm  # dependencies from package.json
elide test                      # node:test files
elide serve server.ts           # a module that default-exports { fetch }
  • TypeScript runs with no compile step and no tsconfig.json.
  • fetch, Request, Response, Streams, URL and Web Crypto are globals.
  • node:fs, node:http, node:worker_threads and most other built-ins load with or without the node: prefix.
  • A module that default-exports { fetch }, as deno serve expects, serves under elide serve and elide run.
  • Elide.serve({ port, fetch }) takes the same Fetch-style handler as Deno.serve.

Start with JavaScript and TypeScript. Module status is in the API Overview; suite results are in the Compatibility Matrix.

What changes

DenoElide
deno run app.tselide app.ts
npm:, jsr: and https: importsBare specifiers resolved from node_modules
deno add, deno installAdd to package.json, then elide install --ecosystems=npm
deno.lockaube-lock.yaml
deno task buildelide run build; reads package.json scripts, not deno.json tasks
deno test, Deno.testelide test with node:test and node:assert
deno run --inspect app.tselide run --debugger=cdp app.ts
deno run --watch app.tsNo equivalent
--env-fileCall process.loadEnvFile() in code
Deno.serve({ fetch })Elide.serve({ fetch })
Deno.readTextFile, Deno.Commandnode:fs and node:child_process
Web Workernode:worker_threads
deno fmt, deno lint, deno compileNo equivalent for JavaScript or TypeScript

Benchmarks

Startup: hyperfine -N -w 10 on a 24-core Linux workstation, running a hello-world script.

RuntimeCommandMean
Denodeno run hello.js6.1 ± 0.3 ms
Elideelide run hello.js2.1 ± 0.1 ms
Bunbun hello.js1.8 ± 0.2 ms
Nodenode hello.js11.4 ± 0.8 ms

Bun starts faster than Elide.

Serving: wrk -t12 -c256 -d10s against a hello-world server. Each server ran on the same 24 CPUs and wrk on 24 others.

RuntimeRequests/sMean latency
Deno280,6660.89 ms
Elide600,352419 µs
Bun147,7421.70 ms
Node91,4643.22 ms

Every server ran with its defaults: Deno, Bun and Node serve on one thread, Elide on several. This compares defaults, not tuned deployments.

Strengths

  • Starts a hello-world script in 2.1 ms against Deno’s 6.1 ms.
  • Served 600,352 requests per second against Deno’s 280,666, both with default settings.
  • elide serve --contexts=auto server.ts runs several copies of the app, sized from the CPU cores, on Linux.
  • Limits workers, open files, heap and run time, and logs each filesystem decision; see the security model below.
  • The same binary runs WebAssembly, compiles and runs Java and Kotlin, and runs Python after elide setup python.

Weaknesses

  • Everything is allowed until you pass a flag, and no flag denies all network or subprocess access.
  • No Deno global, npm: or jsr: imports, URL imports, watch mode, formatter or linter for TypeScript.
  • Node-API compatibility is 86.8% and WinterTC 95.9% on their test suites.
  • node:http2, node:cluster, node:inspector and node:wasi throw ERR_UNKNOWN_BUILTIN_MODULE.
  • https.createServer throws ERR_HTTPS_SERVER_UNSUPPORTED, and there is no WebSocket global.
  • No macOS Intel build; macOS releases are Apple Silicon only.

Security model

Deno denies access until an --allow-* flag grants it. Elide allows access until a flag restricts it.

DenoElide
No flags: everything deniedNo flags: everything allowed
-A, --allow-allNo flags
--allow-read[=PATHS]--allow-read[=PATHS]; denies all other filesystem access
--allow-write[=PATHS]--allow-write[=PATHS]; denies all other filesystem access
--allow-net[=HOSTS]--allow-net[=HOSTS]
--allow-run[=CMDS]--allow-run[=CMDS]
--deny-net=HOSTS, --deny-run=CMDS--deny-net=HOSTS, --deny-run=CMDS
--deny-read, --deny-writeNo equivalent; grant only the paths you need
--allow-env[=NAMES]No equivalent; process.env is always readable, and --allow-env scopes elide.pkl
--allow-ffiAllowed; --no-native denies native access
Prompt for a missing permissionNo prompt; the call fails and names the flag to add

Elide is more permissive in three places:

  • --sandbox restricts the filesystem only. Network and subprocesses stay open until --allow-net=HOSTS, --allow-run=CMDS or a --deny-* flag scopes them.
  • A bare --allow-net or --allow-run, or an empty value, allows everything.
  • Programs read every environment variable through process.env.

Elide adds these controls to the permission flags:

FlagEffect
--fs-auditLog each filesystem decision to stderr.
--limit=workers=N, --limit=fds=NLimit live workers and open node:fs handles.
--max-mem=SIZELimit the heap size.
--timeout=DURATIONStop the run after DURATION with exit 124.

A Deno command and the closest Elide command:

deno run --allow-read=. --allow-net=api.example.com app.ts
elide --allow-read=. --allow-net=api.example.com --allow-run=git --timeout=30s app.ts

--sandbox=trusted is the only available profile. See Sandbox and Limits.

Next steps