Skip to content

/commands/deno/deno-compile

deno compile: build a standalone executable from a TypeScript file

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
Deno
versions
Deno 2.x
os
any

deno compile -o hello main.ts bundles a script and everything it imports, together with a copy of the Deno runtime, into one executable file. The result runs on machines that do not have Deno installed. Permissions are fixed at compile time: pass the --allow-* flags the program needs to deno compile, and add --target to build for another operating system or CPU.

Compile and run

bash
export NO_COLOR=1
cat > main.ts <<'EOF'
const name = Deno.args[0] ?? "world";
console.log(`hello ${name}, HOME is set: ${Deno.env.get("HOME") !== undefined}`);
EOF
npx --yes deno@2 compile --quiet --allow-env=HOME -o hello main.ts
./hello Ada

Output

hello Ada, HOME is set: true

The program reads an environment variable, so it was compiled with --allow-env=HOME; without that flag the compiled program fails at Deno.env.get with a NotCapable error instead of prompting. Arguments after the executable name arrive in Deno.args. On Windows the output file gets an .exe extension automatically. The example uses npx deno@2 so it needs only Node.js; the first compile also downloads the runtime that is embedded in the file.

Options

OptionWhat it does
-o, --output PATHName of the executable (default: derived from the script name)
--allow-read, --allow-net, -APermissions baked into the binary; same syntax as deno run
--target TRIPLECross-compile, for example x86_64-unknown-linux-gnu, aarch64-apple-darwin, x86_64-pc-windows-msvc
--include PATHEmbed extra files or folders the program loads at run time
--icon FILE.icoSet the icon of a Windows executable
--no-terminalWindows only: build a GUI program without a console window
--no-checkSkip type-checking

Arguments placed after the script name are baked in too: deno compile -o srv main.ts --port 8080 makes --port 8080 the first arguments of every run, before the ones the user types.

Pitfalls

  • Dynamic imports and file reads. Only modules Deno can see statically are embedded. A file loaded with Deno.readTextFile or a computed import() must be added with --include, otherwise it is read from disk at run time and is missing on other machines.
  • npm packages with native add-ons (.node files) may not work inside a compiled binary; check them before you rely on it.
  • Code signing. macOS and Windows may warn about an unsigned executable downloaded from the internet. Sign it with the platform tools if you distribute it.
  • Permissions at run time. Users cannot add permissions to a compiled program; recompile with the right flags.

How to confirm it worked

Run the file directly (./hello or hello.exe) on a machine or container without Deno. file hello on Linux and macOS shows the executable format and architecture, which tells you whether --target produced what you expected.

FAQ

Does the compiled program still ask for permissions?

It uses the permissions you passed to deno compile, such as --allow-read or --allow-net, and nothing else. There is no interactive prompt in a compiled binary: an operation without permission fails.

Can I build a Windows .exe on Linux or macOS?

Yes. Pass --target x86_64-pc-windows-msvc. Deno downloads the runtime for that target and writes the executable; supported targets are listed in the deno compile documentation.

Why is the executable so large?

It contains a complete Deno runtime (V8 included) plus your code, so even a one-line program is tens of megabytes. Size grows only a little with your own code.

Sources