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.