# Elide for Bun users

> What works unchanged, which commands and APIs change, and how Elide compares with Bun.

Elide runs the TypeScript, `node:*` modules and npm packages a Bun program uses; the `Bun` global is absent.

## Run the same code

```bash
elide app.ts                    # or: elide run app.ts
elide install --ecosystems=npm  # dependencies from package.json
elide test                      # node:test files
```

- TypeScript runs with no compile step and no `tsconfig.json`.
- `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 }` serves when run, as in Bun.
- `Elide.serve({ port, fetch })` takes the same Fetch-style handler as `Bun.serve`.

Start with [JavaScript and TypeScript](https://elide.help/docs/web). Module status is in the [API Overview](https://elide.help/docs/api-overview); suite
results are in the [Compatibility Matrix](https://elide.help/docs/compatibility).

## What changes

| Bun | Elide |
| --- | --- |
| `bun app.ts` | `elide app.ts` |
| `bun install` | `elide install --ecosystems=npm`; plain `elide install` skips npm |
| `bun.lock` | `aube-lock.yaml` |
| `bun run build` | `elide run build` |
| `bunx tool` | `elide run tool` for a tool in `node_modules/.bin`; no download-and-run |
| `bun test` with `expect` | `elide test` with `node:test` and `node:assert`; `expect` is unavailable |
| `bun --inspect app.ts` | `elide run --debugger=cdp app.ts` |
| `bun --watch`, `bun --hot` | No equivalent |
| `.env` loaded automatically | Call `process.loadEnvFile()` in code |
| `Bun.serve({ fetch })` | `Elide.serve({ fetch })` |
| `bun:sqlite` | `elide:sqlite`; see [Database modules](https://elide.help/docs/api-database) |
| `Bun.file`, `Bun.write`, `Bun.$` | `node:fs` and `node:child_process` |
| Web `Worker` | `node:worker_threads` |
| `bun build`, `bun build --compile` | No equivalent |

## Benchmarks

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

| Runtime | Command | Mean |
| --- | --- | --- |
| Bun | `bun hello.js` | 1.8 ± 0.2 ms |
| Elide | `elide run hello.js` | 2.1 ± 0.1 ms |
| Node | `node hello.js` | 11.4 ± 0.8 ms |
| Deno | `deno run hello.js` | 6.1 ± 0.3 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.

| Runtime | Requests/s | Mean latency |
| --- | --- | --- |
| Bun | 147,742 | 1.70 ms |
| Elide | 600,352 | 419 µs |
| Deno | 280,666 | 0.89 ms |
| Node | 91,464 | 3.22 ms |

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

## Strengths

- Served 600,352 requests per second against Bun's 147,742, both with default settings.
- `elide serve --contexts=auto server.ts` runs several copies of the app, sized from the CPU cores, on Linux.
- Restricts filesystem, network and subprocess access with flags; Bun has no equivalent.
- Limits workers, open files, heap and run time: `--limit=workers=4`, `--limit=fds=128`, `--max-mem=512m`,
  `--timeout=30s`.
- The same binary runs WebAssembly, compiles and runs Java and Kotlin, and runs Python after `elide setup python`.

## Weaknesses

- Bun starts a hello-world script in 1.8 ms; Elide takes 2.1 ms.
- No `Bun` global, bundler, single-file executable, watch mode or `expect` matchers.
- 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

Bun has no permission model: a script can read, write, connect and spawn anything your user can. Elide behaves the
same until you pass a flag.

| Flag | Effect |
| --- | --- |
| `--sandbox` | Deny filesystem access; network and subprocesses stay allowed. |
| `--allow-read[=PATHS]`, `--allow-write[=PATHS]` | Allow reads or writes, everywhere or at the listed paths. |
| `--allow-net[=HOSTS]` | Allow network access, to every host or only the listed ones. |
| `--allow-run[=CMDS]` | Allow subprocesses, any or only the listed commands. |
| `--deny-net=HOSTS`, `--deny-run=CMDS` | Deny hosts or commands even when allowed. |
| `--fs-audit` | Log each filesystem decision to stderr. |
| `--limit=workers=N`, `--limit=fds=N` | Limit live workers and open `node:fs` handles. |
| `--max-mem=SIZE` | Limit the heap size. |
| `--timeout=DURATION` | Stop the run after `DURATION` with exit `124`. |

```bash
elide --allow-read=. --allow-net=localhost --allow-run=git app.ts
```

A denied call names the flag to add:

```text
TypeError: fetch to 'example.com:443' is not permitted; grant it with --allow-net=example.com
```

`--sandbox=trusted` is the only available profile. See [Sandbox and Limits](https://elide.help/docs/sandbox).

## Next steps

- [Installation](https://elide.help/docs/installation)
- [JavaScript and TypeScript](https://elide.help/docs/web)
- [Sandbox and Limits](https://elide.help/docs/sandbox)
