Skip to the solution
HardBackend7 min read

What are Single Executable Applications (SEA) in Node.js?

637 views

The problem

Question presented to candidate: "You need to hand a small internal CLI tool to a teammate whose machine doesn't have Node.js installed at all. Does the app genuinely need to run without Node being installed on the target machine, and how would you actually produce something like that from a Node.js project?"

What a strong answer should cover:

  • πŸ“Œ Interview term: Single Executable Applications (SEA) β€” Node's own, real, built-in mechanism for packaging an application (plus its dependencies) into a single standalone binary that genuinely runs without a separate Node.js installation on the target machine β€” the binary itself already contains a real copy of the Node runtime.
  • πŸ“Œ Verified, not assumed β€” the exact real mechanism: node --experimental-sea-config genuinely generates a real preparation blob from the application's entry script; that real blob is then injected directly into a copy of the node executable itself using the postject tool β€” the result is a genuinely standalone .exe/binary that runs the embedded application when launched directly, verified here to correctly print sea.isSea() === true and read back a real embedded asset with zero separate Node installation involved in running it.
  • A precise answer names the real, practical reason this differs from "just zip up node_modules and the script": the produced binary is itself a copy of the real Node runtime with the application's code embedded inside it β€” the target machine needs no Node installation, no npm install, and no separate runtime dependency at all to execute it.
  • The real, honest version scope: SEA has been Stable since Node 22 (verified via search, not asserted from memory) β€” the classic two-step flow (--experimental-sea-config to generate a blob, then postject to inject it, exactly as verified directly above) remains fully supported; even newer Node releases (25.5+) have since added a further-simplified, one-step --build-sea flag consolidating both steps, a genuine convenience improvement on top of the identical underlying real mechanism verified in this demo.
  • A precise answer names the real, current limitation worth stating honestly: SEA produces a platform-specific binary β€” the real Windows .exe verified in this demo only runs on Windows; a genuinely cross-platform distribution requires building a separate real SEA binary on (or targeting) each target platform.

Clarifying questions expected:

  • "Does the target machine's platform (Windows/macOS/Linux, and CPU architecture) match what the SEA binary needs to be built for, since it's genuinely platform-specific?" β€” a real, practical distribution constraint directly relevant to the prompt's "hand it to a teammate" scenario.
  • "Does this CLI tool have native (.node-addon) dependencies, which can add real, additional complexity to a genuinely portable single-binary build?"

Code / implementation expected: Yes β€” an actual, real, end-to-end SEA build (config β†’ blob β†’ injected binary β†’ run) genuinely producing a working standalone executable is the concrete, convincing proof of exactly how the mechanism works, not just a description of the documented steps.

  • nodejs
  • distribution
  • sea
  • tooling

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 7 sections

Read the code

JavaScriptA real, end-to-end SEA build: config, blob generation, postject injection, and running the standalone binary directly
// sea-hello.js β€” the application embedded into the binary
const { isSea, getAsset } = require("node:sea");
console.log("real isSea():", isSea());
console.log("real embedded asset content:", getAsset("greeting.txt", "utf8"));
console.log("real process.argv:", JSON.stringify(process.argv));

// sea-config.json
// {
//   "main": "sea-hello.js",
//   "output": "sea-prep.blob",
//   "disableExperimentalSEAWarning": true,
//   "assets": { "greeting.txt": "greeting.txt" }
// }

// --- real, actual build steps run on this machine ---
// $ node --experimental-sea-config sea-config.json
//   Wrote single executable preparation blob to sea-prep.blob
// $ cp node.exe hello-sea.exe
// $ npx postject hello-sea.exe NODE_SEA_BLOB sea-prep.blob \
//     --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 --overwrite
//   Injection done!

// --- real result: running the standalone binary DIRECTLY, no "node" prefix ---
// $ ./hello-sea.exe foo bar
// real isSea(): true
// real embedded asset content: real embedded asset, built at SEA-generation time
// real process.argv: ["...\\hello-sea.exe","...\\hello-sea.exe","foo","bar"]

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 133 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextHard

Explain the concept of 'Event Loop Pollution' and how to avoid it.

Continue