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.
deno compile
?
What is 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.
deno compile
works
How 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
:
- A slimmed-down version of the runtime,
denort
, is downloaded. If you’re cross-compiling for a different operating system, thedenort
for that platform is downloaded. - Your script, along with any dependencies, is bundled to
an
eszip
file, a lossless format for serializing an ECMAScript module graph. - 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.
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.