How to Compile or Bundle Deno Applications: Native Executables and JS Bundles Explained
Deno provides two first-class commands for distributing applications—deno compile creates standalone native executables containing the V8 engine and runtime, while deno bundle generates single JavaScript files via esbuild integration suitable for browsers or Node.js.
Deno offers robust tooling for shipping TypeScript and JavaScript applications without requiring end-users to install the runtime. Whether you need a self-contained binary for CLI tools or a portable module for web deployment, mastering how to compile or bundle Deno applications streamlines your production workflow. Both commands leverage Deno's advanced module resolution, npm integration, and TypeScript transpilation pipeline.
Using deno compile to Build Native Executables
The deno compile command transforms your application into a self-contained native executable. This binary includes the JavaScript/TypeScript source, the V8 engine, and the Deno runtime, allowing distribution to users who do not have Deno installed.
The Compilation Pipeline
According to the Deno source code in [cli/tools/compile.rs](https://github.com/denoland/deno/blob/main/cli/tools/compile.rs), the compilation process follows five distinct phases:
-
Flag Parsing: The CLI creates
CliOptionsfrom arguments and aCompileFlagsstruct that handles--output,--target, and permission flags. -
Temporary Node Modules: When the entrypoint uses npm specifiers, the compiler creates a temporary
node_modulesdirectory viacreate_temp_node_modules_dir(lines 40-53) to resolve packages during the build. -
Module Graph Construction:
CliFactory::from_flagsgenerates a factory that builds a module graph usingmodule_graph_creator.create_graph_and_maybe_check(lines 88-105). This resolves all imports, applies TypeScript type checking if enabled, and produces a code-only graph. -
Binary Generation: The
BinaryWriterfromdeno_runtime(located inruntime/standalone/binary.rs) embeds the module graph into a self-extracting ELF, PE, or Mach-O binary. The writer outputs to a temporary file, sets executable permissions (PermissionsExt::from_mode(0o755)), and renames it to the final output path (lines 33-44, 77-85). -
Cross-Platform Naming: The
get_os_specific_filepathfunction automatically appends.exewhen targeting Windows (lines 29-45), ensuring correct extensions regardless of the host platform.
Cross-Platform Compilation
Deno supports cross-compilation through the --target flag. You can build Windows executables from Linux or macOS, and vice versa, by specifying the target triple:
deno compile --target x86_64-pc-windows-msvc --output app.exe ./main.ts
The compiler downloads the appropriate Deno runtime binary for the target architecture and embeds your application code, producing a fully standalone executable.
Using deno bundle to Create JavaScript Bundles
The deno bundle command produces a single JavaScript file (ESM or IIFE) that runs in browsers, Node.js, or other JavaScript runtimes. This command delegates to esbuild via the deno_bundle_runtime crate, with core logic residing in [cli/tools/bundle/mod.rs](https://github.com/denoland/deno/blob/main/cli/tools/bundle/mod.rs).
The Esbuild Integration Pipeline
The bundling workflow relies on three primary components defined in the source:
Entry Resolution: The bundle_init function (lines 26-38) resolves entry URLs using Deno's native resolver, ensuring import maps, npm specifiers, and Node.js built-ins are handled identically to normal execution.
Plugin Bridge: [cli/tools/bundle/provider.rs](https://github.com/denoland/deno/blob/main/cli/tools/bundle/provider.rs) implements CliBundleProvider, which acts as a bridge between Deno's module system and esbuild through three critical callbacks:
on_resolve: Handles import resolution, virtual modules for HTML entrypoints, and external module marking (lines 35-115)on_load: Loads file contents including TypeScript transpilation, returning appropriate esbuild loader types (JS, TS, CSS, JSON) (lines 24-71)on_end: Delivers the finalBuildResponsevia async channel (lines 84-88)
Post-Processing: After esbuild completes, process_result applies optional transformations including require shim replacement for Deno compatibility and minification before writing to the --output location.
HTML Entrypoints and Watch Mode
Deno supports bundling HTML files directly. When provided with an HTML entrypoint, the bundler generates a virtual module via html::load_html_entrypoint (lines 47-61) that imports all scripts referenced in the HTML, enabling complete application bundling including assets.
For development workflows, bundle_watch (in mod.rs) sets up a file watcher that rebuilds the bundle automatically when source files change.
Choosing Between Compilation and Bundling
Select the appropriate command based on your distribution requirements:
-
Use
deno compilewhen you need a single binary that runs without Deno installed. Ideal for CLI tools, system utilities, or server applications where you want minimal deployment friction. -
Use
deno bundlewhen targeting browsers, Node.js, or other JavaScript runtimes. Essential for frontend applications, library distribution, or environments where a full Deno runtime is unavailable. -
Both support npm:
compileembeds a temporarynode_modulestree into the binary, whilebundleresolves npm specifiers through the esbuild plugin system.
Practical Examples
Compile a script to a native binary with networking permissions:
deno compile --allow-net --output server ./server.ts
Cross-compile for Windows from macOS or Linux:
deno compile --target x86_64-pc-windows-msvc --output app.exe ./main.ts
Create a minified ESM bundle for browsers:
deno bundle --minify --output dist/app.min.js ./src/main.ts
Bundle an HTML entrypoint with all referenced scripts:
deno bundle --output-dir dist/ index.html
Enable watch mode for automatic rebuilds during development:
deno bundle --watch --output dist/bundle.js ./src/main.ts
Summary
deno compileproduces standalone native executables by embedding your code with the V8 engine and Deno runtime using theBinaryWriterinruntime/standalone/binary.rs.deno bundlegenerates portable JavaScript bundles using esbuild integration viacli/tools/bundle/mod.rsand theCliBundleProviderbridge.- Both commands fully support npm packages, import maps, and TypeScript transpilation through Deno's resolver system.
- Cross-compilation is available via
--targetflags, while bundling offers--watchmode and HTML entrypoint support for comprehensive asset management.
Frequently Asked Questions
What is the difference between deno compile and deno bundle?
deno compile creates a native binary executable specific to your operating system (or cross-compilation target) that contains the Deno runtime, allowing the program to run without Deno installed. deno bundle produces a single JavaScript file that requires a JavaScript runtime (like Deno, Node.js, or a browser) to execute, making it suitable for web deployment or environments where you cannot install native binaries.
Can I cross-compile Deno applications for different platforms?
Yes. The deno compile command supports cross-compilation through the --target flag, accepting platform triples like x86_64-pc-windows-msvc, x86_64-unknown-linux-gnu, or aarch64-apple-darwin. According to the implementation in cli/tools/compile.rs, the compiler automatically handles OS-specific filename extensions (such as .exe for Windows) via get_os_specific_filepath regardless of your host platform.
Does deno bundle support npm packages?
Yes. The bundler resolves npm specifiers through the same resolver used by the runtime, implemented in cli/tools/bundle/provider.rs. The on_resolve callback handles npm package resolution and external module marking, allowing you to bundle applications that depend on npm dependencies alongside Deno's native modules.
How does Deno handle HTML entrypoints when bundling?
When bundling an HTML file, Deno generates a virtual entry module using html::load_html_entrypoint (found in cli/tools/bundle/mod.rs). This virtual module imports all scripts referenced in the HTML file, allowing esbuild to trace dependencies and bundle the entire application including JavaScript, CSS, and assets into the output directory.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →