Skip to main content
Deno 2 is finally here 🎉️
Learn more
Use deno compile to create cross platform single executable binaries.

Self-contained Executable Programs with Deno Compile

Since Deno v1.6, the deno compile command has empowered developers to turn JavaScript and TypeScript programs into single, standalone binaries that run on all major platforms—no dependencies, no additional installs. This has big implications:

  • Cross-platform compatibility: Distribute a single binary that works without a Deno runtime or dependencies.
  • Bundled assets: Package everything your app needs inside the binary for easy portability.
  • Streamlined deployment: Ship one binary to production, reducing complexities.
  • Improved startup times: Faster launch times compared to typical server or runtime setups.

Since Deno 2, we’ve introduced even more improvements to deno compile, like support for npm packages, web workers, cross-compilation, smaller binary sizes, and code signing with custom icons. These upgrades mean you can now compile not only scripts but also complete applications like desktop games directly to native binaries.

In this post, we’ll explore what makes deno compile unique, how it works, and examples of different use cases that highlight its advantages over alternatives in the ecosystem.

🚨️ Deno 2 is here. 🚨️

With backwards compatibility with Node/npm, built-in package management, all-in-one zero-config toolchain, and native TypeScript and web API support, writing JavaScript has never been simpler.

What is deno compile?

Deno offers a zero-config toolchain for JavaScript and TypeScript, so you don’t need to cobble together different tools before writing a single line of code. One subcommand is deno compile, which lets you build a single binary from your JavaScript or TypeScript code. And unlike Node’s 8-step compilation process, deno compile is just one command.

This subcommand lets you skip install requirements and run binaries on systems without Deno installed, across platforms like Windows, macOS, and Linux. Deno’s compiled binaries are also optimized for size. If you’re coming from Node, this simplicity reduces friction when moving code between environments, especially when cross-compiling for different OS targets.

How deno compile works

Though it’s called “compile,” deno compile doesn’t compile JavaScript in the traditional sense. Instead, it embeds your JavaScript and TypeScript into a special Deno runtime binary, called denort (short for “Deno runtime”).

Here’s a high-level overview of the process when you execute deno compile:

  1. A slimmed-down version of the runtime, denort, is downloaded. If you’re cross-compiling for a different operating system, the denort for that platform is downloaded.
  2. Your script, along with any dependencies, is bundled to an eszip file, a lossless format for serializing an ECMAScript module graph.
  3. The bundle is injected into the denort binary using Sui.

By embedding the bundle into a section of the executable, the outputted binary can still be codesigned.

Examples

Basic self-contained binary

To start, let’s look at how easy it is to create a single executable from a TypeScript script.

// main.ts
import open from "jsr:@rdsq/open";

await open("https://www.youtube.com/watch?v=dQw4w9WgXcQ");

Compiling it is as simple as:

deno compile -A -o runme main.ts

This outputs an executable binary (runme) that includes all required dependencies. Now you can share this single file on any platform, without requiring the end user to install Deno.

Note that you can pass opt-in permission flags, such as --allow-net, in the deno compile command. The permission flags will then be preserved in the compiled binary, giving you an added layer of security over how your binary can be used.

Cross-compiling for Windows

Say you want to share the app with a Windows user. Using the --target flag, you can cross-compile it for Windows:

deno compile --allow-all -o runme --target x86_64-pc-windows-msvc main.ts

Now you’ve got runme.exe, a Windows-compatible binary. You can even add a custom icon with the --icon flag for a more polished look:

deno compile --allow-all -o runme --target x86_64-pc-windows-msvc --icon icon.ico main.ts

Code signing

Code signing ensures that your binary is verified and trustworthy, which is critical for software distribution. Deno simplifies this, even on macOS, where you can use codesign as with any other app.

Let’s confirm our binary’s integrity:

codesign --verify -vv ./runme
./runme: valid on disk
./runme: satisfies its Designated Requirement

The binary we compiled is properly code signed and ready for publishing.

Compiling NPM packages

Of course it’s possible to use NPM packages with deno compile. This approach is ideal for performance-sensitive CI environments or when you need a single portable version of a tool.

As an example, let’s use deno compile on npm itself:

deno compile -A npm:npm

Running the compiled npm binary is simple, and it even shows performance boosts. In tests, Deno-compiled npm binaries ran ~1.9x faster than regular npm:

# hyperfine "./npm -v" "npm -v"
Benchmark 1: ./npm -v
  Time (mean ± σ):      40.1 ms ±  2.0 ms    [User: 37.7 ms, System: 5.3 ms]
  Range (min … max):    38.9 ms … 51.8 ms    71 runs

Benchmark 2: npm -v
  Time (mean ± σ):      75.2 ms ±  7.6 ms    [User: 59.1 ms, System: 9.0 ms]
  Range (min … max):    69.2 ms … 105.0 ms   40 runs

Summary
  ./npm -v ran
    1.87 ± 0.21 times faster than npm -v

This approach works with other popular npm tools too, like prettier and eslint, giving you faster, more portable versions.

Games and Desktop apps

deno compile also opens up the potential for bundling web-based games and apps as native desktop executables. For example, you could take an HTML/CSS/JavaScript game and turn it into a binary that’s easy to share and launch on any desktop.

Watch the video demo of bundling HTML games with deno compile.

Take a look at this Flappybird clone, which can be compiled into a desktop app using Deno:

deno compile --unstable-ffi --env -o flappybird -A main.js

Bundling assets

Though deno compile doesn’t currently support bundling assets directly (yet!), it’s possible to convert .png or other asset files into base64-encoded .js files and import them into your project, allowing them to be included in the final binary. This method, while a workaround, enables developers to package games and other assets in a single executable.

What’s next

We’re continually improving deno compile based on your feedback, with updates on the way to streamline asset bundling, support more frameworks like Svelte, reduce binary sizes, and improve startup times even further with caching.

🚨️ Want to learn more Deno? 🚨️

Check out our new Learn Deno tutorial series, where you’ll learn:

…and more, in short, bite-sized videos. New tutorials published every Tuesday and Thursday.