On this page
- Flags
- Framework detection
- Watch mode
- Cross Compilation
- The denort binary
- Icons
- Dynamic Imports
- Including Data Files or Directories
- Workers
- Bundling dependencies
- Self-Extracting Executables
- Code Signing
- Persistent storage in executables
- Type checking options
- Dependency management options
- Options
- Compile options
- File watching options
deno compile
Flags Jump to heading
As with deno install, the runtime flags
used to execute the script must be specified at compilation time. This includes
permission flags.
deno compile --allow-read --allow-net jsr:@std/http/file-server
Script arguments can be partially embedded.
deno compile --allow-read --allow-net jsr:@std/http/file-server -p 8080
./file_server --help
Framework detection Jump to heading
Starting in Deno 2.8, deno compile . (or deno compile <directory>) detects
common web frameworks and produces an entrypoint that knows how to start them.
The detected build script is run first, so the compiled binary always contains a
fresh build.
Supported frameworks:
- Next.js
- Astro
- Fresh (1.x and 2.x)
- Remix
- SvelteKit
- Nuxt
- SolidStart
- TanStack Start
- Vite (SSR, plus SPA/MPA projects served as static output)
# In a Next.js / Astro / Fresh / etc. project
deno compile .
# Or pointing at a specific app directory
deno compile ./apps/web
Generated entrypoints use import.meta.dirname so framework asset paths resolve
correctly against the virtual filesystem
inside the compiled binary.
If the project doesn't match any supported framework, deno compile will error
out.
Watch mode Jump to heading
Pass --watch to rebuild the executable whenever a file in the compile graph
changes:
deno compile --watch main.ts
Use --watch-exclude to keep specific paths from triggering a rebuild, and
--no-clear-screen to preserve the terminal output between rebuilds:
deno compile --watch --watch-exclude=./dist --no-clear-screen main.ts
Cross Compilation Jump to heading
You can cross-compile binaries for other platforms by using the --target flag.
# Cross compile for Apple Silicon
deno compile --target aarch64-apple-darwin main.ts
# Cross compile for Windows with an icon
deno compile --target x86_64-pc-windows-msvc --icon ./icon.ico main.ts
Supported Targets Jump to heading
Deno supports cross compiling to all targets regardless of the host platform.
| OS | Architecture | Target |
|---|---|---|
| Windows | x86_64 | x86_64-pc-windows-msvc |
| macOS | x86_64 | x86_64-apple-darwin |
| macOS | ARM64 | aarch64-apple-darwin |
| Linux | x86_64 | x86_64-unknown-linux-gnu |
| Linux | ARM64 | aarch64-unknown-linux-gnu |
The denort binary Jump to heading
deno compile embeds your program into denort ("Deno runtime"): a stripped
build of Deno that contains only what's needed to run a compiled program, with
none of the tooling subcommands. Using denort as the base instead of the full
deno binary is what keeps compiled executables smaller.
The first time you compile for a given Deno version and target, Deno downloads
the matching denort-<target>.zip from dl.deno.land and caches it in
DENO_DIR. This is also how cross-compilation works: compiling with --target
fetches that platform's denort. Subsequent compiles reuse the cached binary
and work offline.
To use a custom or locally built runtime as the base, set the DENORT_BIN
environment variable to its path. Deno also picks up a denort binary placed
next to the deno executable.
Icons Jump to heading
It is possible to add an icon to the executable by using the --icon flag when
targeting Windows. The icon must be in the .ico format.
deno compile --icon icon.ico main.ts
# Cross compilation with icon
deno compile --target x86_64-pc-windows-msvc --icon ./icon.ico main.ts
Dynamic Imports Jump to heading
By default, statically analyzable dynamic imports (imports that have the string
literal within the import("...") call expression) will be included in the
output.
// calculator.ts and its dependencies will be included in the binary
const calculator = await import("./calculator.ts");
But non-statically analyzable dynamic imports won't:
const specifier = condition ? "./calc.ts" : "./better_calc.ts";
const calculator = await import(specifier);
To include non-statically analyzable dynamic imports, specify an
--include <path> flag.
deno compile --include calc.ts --include better_calc.ts main.ts
Including Data Files or Directories Jump to heading
Starting in Deno 2.1, you can include files or directories in the executable by
specifying them via the --include <path> flag.
deno compile --include names.csv --include data main.ts
Then read the file relative to the directory path of the current module via
import.meta.dirname:
// main.ts
const names = Deno.readTextFileSync(import.meta.dirname + "/names.csv");
const dataFiles = Deno.readDirSync(import.meta.dirname + "/data");
// use names and dataFiles here
Note this currently only works for files on the file system and not remote files.
--include treats embedded .js and .ts files as module-graph roots, so it
resolves and transpiles them. To embed files exactly as they are, without any
module resolution, use --include-as-is instead. This is the right choice for
pre-built frontend bundles (for example Vite or webpack output) that are already
processed and would fail to resolve as Deno modules:
deno compile --include-as-is ./dist main.ts
Configuring include / exclude in deno.json Jump to heading
The --include and --exclude paths can be set declaratively in deno.json so
you don't have to repeat them on every deno compile invocation:
{
"compile": {
"include": ["names.csv", "data", "worker.ts"],
"exclude": ["data/secrets", "**/*.test.ts"]
}
}
CLI flags are merged with the config: --include and --exclude add to the
lists in deno.json rather than replacing them. See the
Compile config section in the
configuration guide for more details, including how to declare permissions on
the same block.
Workers Jump to heading
Similarly to non-statically analyzable dynamic imports, code for workers is not included in the compiled executable by default. There are two ways to include workers:
- Use the
--include <path>flag to include the worker code.
deno compile --include worker.ts main.ts
- Import worker module using a statically analyzable import.
// main.ts
import "./worker.ts";
deno compile main.ts
Bundling dependencies Jump to heading
--bundle is experimental and subject to change. Some dynamic patterns are not
yet supported (see Limitations below).
By default, deno compile embeds the entire resolved node_modules tree in the
executable. For projects with many npm dependencies this can make binaries large
and slow to start. The --bundle flag instead runs your entrypoint through the
bundler before embedding, so only the code your program actually reaches ends up
in the binary.
deno compile --bundle main.ts
For a pure-ESM dependency tree, tree-shaking removes everything unused and the
npm payload is dropped entirely, producing a much smaller binary. When a
CommonJS package or a native addon (.node) is reached, the relevant packages
are embedded so they keep working at runtime, but unreached packages are still
left out.
--bundle understands several real-world patterns automatically:
- CommonJS and native addons — CJS dependencies and
.nodenative addons are detected and the packages that provide them are embedded. - Workers —
new Worker(new URL("./worker.ts", import.meta.url), ...)calls are discovered, each worker is bundled separately and embedded alongside the main bundle. package.jsonreads — packages that read their ownpackage.jsonat runtime (for example to report a version) have it included automatically.
Minifying the bundle Jump to heading
Combine --bundle with --minify to minify the bundled output. This reduces
both the embedded bundle size and runtime memory use, at the cost of less
readable stack traces.
deno compile --bundle --minify main.ts
--minify is only meaningful together with --bundle.
Limitations Jump to heading
Because bundling relies on statically analyzing your code, patterns that can't be traced are dropped from the binary:
- Dynamic
require()/import()of specifiers that aren't string literals. - Workers spawned with computed URLs, or spawned from transitive dependencies rather than your own source.
If your program relies on these, either keep them statically analyzable, add the
needed files with --include, or
compile without --bundle.
Self-Extracting Executables Jump to heading
By default, compiled executables serve embedded files from an in-memory virtual
file system. The --self-extracting flag changes this behavior so that the
binary extracts all embedded files to disk on first run and uses real file
system operations at runtime.
deno compile --self-extracting main.ts
This is useful for scenarios where code needs real files on disk, such as native addons or native code that reads relative files.
The extraction directory is chosen in order of preference:
<exe_dir>/.<exe_name>/<hash>/(next to the compiled binary)- Platform data directory fallback:
- Linux:
$XDG_DATA_HOME/<exe_name>/<hash>or~/.local/share/<exe_name>/<hash> - macOS:
~/Library/Application Support/<exe_name>/<hash> - Windows:
%LOCALAPPDATA%\<exe_name>\<hash>
- Linux:
Files are only extracted once — subsequent runs reuse the extracted directory if it already exists and the hash matches.
Trade-offs Jump to heading
Self-extracting mode enables broader compatibility, but comes with some trade-offs:
- Initial startup cost: The first run takes longer due to file extraction.
- Disk usage: Extracted files take up additional space on disk.
- Memory usage: Higher memory usage since embedded content can no longer be referenced as static data.
- Tamper risk: Users or other code can modify the extracted files on disk.
Code Signing Jump to heading
macOS Jump to heading
By default, on macOS, the compiled executable will be signed using an ad-hoc
signature which is the equivalent of running codesign -s -:
deno compile -o main main.ts
codesign --verify -vv ./main
./main: valid on disk
./main: satisfies its Designated Requirement
You can specify a signing identity when code signing the executable just like you would do with any other macOS executable:
codesign -s "Developer ID Application: Your Name" ./main
Refer to the official documentation for more information on codesigning and notarization on macOS.
Windows Jump to heading
On Windows, the compiled executable can be signed using the SignTool.exe
utility.
deno compile -o main.exe main.ts
signtool sign /fd SHA256 main.exe
Persistent storage in executables Jump to heading
A compiled binary is treated as a standalone application, so origin-bound
storage persists across runs in the platform's application data directory
(%LOCALAPPDATA% on Windows, ~/Library/Application Support on macOS,
$XDG_DATA_HOME on Linux):
localStorageand the Web Cache API read and write to that directory.Deno.openKv()called without a path opens a persistent database there instead of falling back to an in-memory one.
Each compiled app gets its own location derived from its identity, so separate
apps do not share storage. That identity comes from the --app-name flag, which
is baked in at compile time and falls back to the output file name when omitted:
deno compile --app-name my-app main.ts
Because the name (not the module path) drives the directory, the store stays
stable across runs even if you rename the binary, two binaries built with the
same --app-name share a store, and differently named apps stay isolated.
Recompiling with a different --app-name starts a fresh store.
deno compile [OPTIONS] [SCRIPT_ARG]...Compiles the given script into a self contained executable.
deno compile --allow-read --allow-net jsr:@std/http/file-server
deno compile --output file_server jsr:@std/http/file-server
Any flags specified which affect runtime behavior will be applied to the resulting binary.
This allows distribution of a Deno application to systems that do not have Deno installed. Under the hood, it bundles a slimmed down version of the Deno runtime along with your JavaScript or TypeScript code.
Cross-compiling to different target architectures is supported using the --target flag.
On the first invocation of deno compile, Deno will download the relevant binary and cache it in $DENO_DIR.
Type checking options Jump to heading
--check<CHECK_TYPE>optionalSet type-checking behavior. This subcommand type-checks local modules by default, so passing --check is redundant; pass --check=all to also type-check remote modules. Alternatively, use the 'deno check' subcommand.
--no-check<NO_CHECK_TYPE>optionalSkip type-checking. If the value of "remote" is supplied, diagnostic errors from remote modules will be ignored.
Dependency management options Jump to heading
--cached-onlyRequire that remote dependencies are already cached.
--frozen<BOOLEAN>optionalError out if lockfile is out of date.
Load import map file from local file or remote URL.
--lock<FILE>optionalCheck the specified lock file. (If value is not provided, defaults to "./deno.lock").
--no-lockDisable auto discovery of the lock file.
--no-npmDo not resolve npm modules.
--no-remoteDo not resolve remote modules.
--node-modules-dir<MODE>optionalSelects the node_modules directory mode for npm packages (not a path). One of: auto (create a local node_modules directory and install npm packages into it), manual (use the existing local node_modules directory, do not modify it), none (do not use a local node_modules directory; resolve npm packages from the global cache). Defaults to auto when the flag is passed without a value.
--node-modules-linker<MODE>Sets the linker mode for npm packages (isolated or hoisted).
--reload, -r<CACHE_BLOCKLIST>optionalReload source code cache (recompile TypeScript). With no value, reloads everything. Pass a comma-separated list of specifiers to reload only those modules; npm: reloads all npm modules; npm:chalk reloads a single npm module; jsr:@std/http/file-server,jsr:@std/assert/assert-equals reloads specific modules.
--vendor<vendor>optionalToggles local vendor folder usage for remote modules and a node_modules folder for npm packages.
Options Jump to heading
--allow-scripts<PACKAGE>optionalAllow running npm lifecycle scripts for the given packages
Note: Scripts will only be executed when using a node_modules directory (--node-modules-dir).
--cert<FILE>Load certificate authority from PEM encoded file.
--conditions<conditions>Use this argument to specify custom conditions for npm package exports. You can also use DENO_CONDITIONS env var. .
Configure different aspects of deno including TypeScript, linting, and code formatting.
Typically the configuration file will be called deno.json or deno.jsonc and
automatically detected; in that case this flag is not necessary.
--env-file<FILE>optionalLoad environment variables from local file Only the first environment variable with a given key is used. Existing process environment variables are not overwritten, so if variables with the same names already exist in the environment, their values will be preserved. Where multiple declarations for the same environment variable exist in your .env file, the first one encountered is applied. This is determined by the order of the files you pass as arguments.
--ext<ext>Set content type of the supplied file.
--location<HREF>Value of globalThis.location used by some web APIs.
--minimum-dependency-age<minimum-dependency-age>(Unstable) The age in minutes, ISO-8601 duration or RFC3339 absolute timestamp (e.g. '120' for two hours, 'P2D' for two days, '2025-09-16' for cutoff date, '2025-09-16T12:00:00+00:00' for cutoff time, '0' to disable).
--no-code-cacheDisable V8 code cache feature.
--no-configDisable automatic loading of the configuration file.
--preload<FILE>A list of files that will be executed before the main module.
--require<FILE>A list of CommonJS modules that will be executed before the main module.
--seed<NUMBER>Set the random number generator seed.
--v8-flags<V8_FLAGS>optionalTo see a list of all available flags use --v8-flags=--help
Flags can also be set via the DENO_V8_FLAGS environment variable.
Any flags set with this flag are appended after the DENO_V8_FLAGS environment variable.
Compile options Jump to heading
--app-name<app-name>Stable identity for the compiled app.
Determines where origin-bound storage such as the default Deno.openKv(),
localStorage and caches is persisted (under the platform's app data directory).
Defaults to the output file name. Set this to keep storage stable across renames.
--bundleExperimental. Bundle the entrypoint with esbuild before embedding, instead of shipping the whole node_modules tree. Produces a smaller binary with faster startup, at the cost of dropping dynamic require/import patterns that can't be statically traced.
--exclude<exclude>Excludes a file/directory in the compiled executable. Use this flag to exclude a specific file or directory within the included files. For example, to exclude a certain folder in the bundled node_modules directory.
--exclude-unused-npmEmbed only the npm packages reachable from the module graph (managed npm; no node_modules directory).
Without this flag the full managed npm snapshot from the lockfile / package.json is embedded.
Reduces binary size when the lockfile contains packages the entrypoint does not import.
Skips packages that are only reached through non-statically-analyzable dynamic imports;
pass those with --include npm:
--icon<icon>Set the icon of the executable on Windows (.ico).
--include<include>Includes an additional module or file/directory in the compiled executable. Use this flag if a dynamically imported module or a web worker main module fails to load in the executable or to embed a file or directory in the executable. This flag can be passed multiple times, to include multiple additional modules.
--minifyExperimental. Minify the bundled output. Only meaningful with --bundle.
Reduces both the embedded bundle size and runtime memory use, at the cost of less readable stack traces.
--no-terminalHide terminal on Windows.
--output, -o<output>Output file (defaults to $PWD/
--self-extractingCreate a self-extracting binary that extracts the embedded file system to disk on first run and then runs from there.
--target<target>Target OS architecture.
File watching options Jump to heading
--no-clear-screenDo not clear terminal screen when under watch mode.
--watchWatch for file changes and restart process automatically. Only local files from entry point module graph are watched.
--watch-exclude<FILES>optionalExclude provided files/patterns from watch mode.