# Compile to a single-file executable

`deno compile` packs the entry module graph and the trimmed `denort` runtime into one self-contained executable. Target machines do not need Deno installed.

## Basic usage

```bash
deno compile --output=server main.ts
./server
```

The output is a platform-specific binary. Runtime flags must be declared at compile time, including permissions:

```bash
deno compile --allow-net --allow-env=PORT --output=server main.ts
```

<Callout type="warn" title="Permissions are frozen at compile time">
A compiled binary does not accept `--allow-*` flags at runtime. The permission set is fixed when you run `deno compile` and baked into the artifact; it can be neither tightened nor relaxed later. Compile with least privilege and never burn `-A` into a file you distribute.
</Callout>

## Cross-compilation

`--target` cross-compiles from any host platform. Five target triples are currently supported:

| Target | Platform |
| --- | --- |
| `x86_64-pc-windows-msvc` | Windows x86_64 |
| `x86_64-apple-darwin` | macOS x86_64 |
| `aarch64-apple-darwin` | macOS ARM64 |
| `x86_64-unknown-linux-gnu` | Linux x86_64 |
| `aarch64-unknown-linux-gnu` | Linux ARM64 |

```bash
deno compile --target=aarch64-unknown-linux-gnu --output=server-linux-arm64 main.ts
```

The matching `denort` binary is downloaded into the `DENO_DIR` cache. Always boot a cross-compiled artifact once on the real target platform; "it compiled" is not a verification.

## Embedding assets

Since Deno 2.1, `--include` embeds files or directories into the binary, readable through `import.meta`-relative paths:

```bash
deno compile --include=./data --include=worker.ts main.ts
```

```ts
const csv = await Deno.readTextFile(import.meta.dirname + "/data/names.csv");
```

- `--include` can be passed multiple times; only local files are supported, remote modules cannot be embedded.
- Embedded `.js` / `.ts` files become module-graph roots and are transpiled. For pre-built frontend bundles use `--include-as-is` to embed them verbatim.
- The `compile` block in `deno.json` declares `include` / `exclude` arrays, which merge with CLI flags.
- The whole resolved `node_modules` tree is embedded by default; the experimental `--exclude-unused-npm` flag embeds only reachable npm packages.

## Boundary with Docker and Deploy

| Scenario | Preferred approach |
| --- | --- |
| Distributing CLI tools or single-file daemons | `deno compile` |
| Services needing system libraries, CAs, a shell, or multi-process setups | [Docker and containers](/en/docs/deploy/docker) |
| HTTP services needing managed TLS, multi-region rollout, and autoscaling | [Deno Deploy](/en/docs/deploy/deno-deploy) |

`deno compile` solves the distribution shape, not process management, rolling upgrades, or certificates. Long-running services still need systemd, an orchestrator, or a hosted platform.

## Known limitations

- Only string-literal dynamic imports are included statically; computed specifiers must be pulled in with `--include`.
- Worker code is not part of the artifact by default; bring it in via `--include` or a static `import "./worker.ts"`.
- Native plugins (FFI, `.node` addons) rely on self-extracting mode, which slows down first runs and uses extra disk; verify per target platform.
- The binary is bound to a Deno version; runtime upgrades mean recompiling and redistributing.

Official reference: [deno compile](https://docs.deno.com/runtime/reference/cli/compile/).
