HomeShip a Node.js app as a single executable binary

Ship a Node.js app as a single executable binary

By · Node.js & JavaScript developer
Published July 5, 2026

What if you could hand someone a single file that runs your Node.js program — no node to install, no npm install, nothing? That's what Single Executable Applications (SEA) do: Node bundles your script together with the runtime into one native binary. It's still an experimental feature, but it works today. Every step below was run on a stock node:26-slim Docker image, and the finished binary was tested on a plain Debian image with no Node installed.

The app

A small CLI. Note two SEA-specific touches: node:sea's isSea() tells you when you're running inside the bundle, and getAsset() reads files you embedded at build time. The argument parsing uses the built-in util.parseArgs, so there are zero dependencies.

// hello.js
const { parseArgs } = require('node:util');
const { isSea, getAsset } = require('node:sea');

const { values } = parseArgs({
  options: { name: { type: 'string', short: 'n', default: 'world' } },
});

console.log(`Hello, ${values.name}!`);
console.log('Running inside a single executable?', isSea());

if (isSea()) {
  console.log('bundled asset:', getAsset('banner.txt', 'utf8').trim());
}

The build config

A small JSON file tells Node what to bundle. The assets map embeds arbitrary files into the binary — here a banner.txt we read back with getAsset().

{
  "main": "hello.js",
  "output": "sea-prep.blob",
  "assets": {
    "banner.txt": "banner.txt"
  }
}

Building the executable

Four steps: generate a preparation blob, copy the node binary under your app's name, inject the blob into that copy with postject, and run it.

# 1. generate the blob from the config
$ node --experimental-sea-config sea-config.json
Wrote single executable preparation blob to sea-prep.blob

# 2. copy the node binary, named after your app
$ cp "$(command -v node)" hello

# 3. inject the blob into the copy
$ npx postject hello NODE_SEA_BLOB sea-prep.blob \
    --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2

# 4. run it
$ ./hello --name codewithnodejs
Hello, codewithnodejs!
Running inside a single executable? true
bundled asset: built with Node.js Single Executable Applications

Proof: it runs with no Node.js installed

The whole point is a runtime-free target. Here's the exact binary running inside a bare debian:bookworm-slim image that has no Node at all — it only needs one shared library (libatomic1):

$ docker run --rm -v "$PWD":/w -w /w debian:bookworm-slim sh -c '
    apt-get install -y libatomic1     # the one extra lib the binary needs
    which node || echo "no node installed"
    ./hello --name debian'
no node installed
Hello, debian!
Running inside a single executable? true
bundled asset: built with Node.js Single Executable Applications

The catches

  • It's big. The binary is ~142 MB, because it embeds the entire Node.js runtime.
  • Still experimental. Running it prints ExperimentalWarning: Single executable application is an experimental feature.
  • Not fully static. The binary is dynamically linked — the target machine still needs the C runtime (glibc) and libatomic. That's why the Debian run installs libatomic1.
  • Per-platform. You're copying this machine's Node binary, so build on the OS and CPU architecture you're targeting — a Linux build won't run on macOS or Windows.
  • CommonJS entry. The main script is evaluated as CommonJS; if your app has imports or dependencies, bundle it to a single file first (esbuild, rollup) and point main at the output.
  • macOS & Windows need extra steps to remove and re-apply code signing after injection.

When it's worth it

SEA shines for distributing a CLI to people who don't have (or don't want) Node, and for dropping a program onto a machine with no runtime installed. It is not a size optimization — for containers, a slim or distroless image is far smaller. Reach for it when "one file, double-click, run" is the goal.

Sources & further reading

About Code with Node.js

This is a personal blog and reference point of a Node.js developer.

I write and explain how different Node and JavaScript aspects work, as well as research popular and cool packages, and of course fail time to time.