NodeJs Single or Standalone Executable
Learn how to create a single or standalone distributable appication for your NodeJs project.
Tags
TLDR 🥱!!!
No TLDR, if not me then NodeJs doc page here is your friend 😤.
Introduction (Short One 🤏🏻) 📜
I hope everyone remembers the Vercel’s pkg package( repo link ). They’ve archived that github repository and no longer maintain it, and that’s because :-
- NodeJs from Version 21+ itself has the ability to create single executables.
- At the time of writing this post, it’s still an experimental feature, but it’s there and it works, and I’ll show you how.
- If you try and use the pkg package with NodeJs version 18+ (ha 😏 18+), it sh*t’s the bed 💩.
Why Do I Need This? 🤔
Well … idk about you, but I needed it 🤷🏻♂️.
I had to make a desktop app where I had to stream large video files, and I mean they were really huge, like 10GB+ huge 😱.
And if you’re familiar with ExpressJs (or Express at NPM ), to stream large files, all you need to do is :-
app.get('/video', (req, res) => { res.sendFile('path/to/massive/video.mp4') });
and it just works 🤨.
Now, if I can just package an external Express server app with this tiny code 👆🏻 running on standalone NodeJs executable, I’m all set 🤘🏻, right?
Well, that’s exactly what we’ll do now 😊.
The Code You Gotta Write 📝
That’s because, at the time of writing this post, this experimental feature only supports the CommonJs module system. Read more here
Pre-Requisites 📝
I’m assuming, you’ve written your jacka*s NodeJs app and you’re ready to package it.
For me, I wrote a bunch of ExpressJs code in a src
folder and the folder/file structure looks like this :-
node_modules src/ - index.js routers/ - file.js package.json
Doesn’t matter what sphagetti code you have in there, as long as it’s in src
, you’re good to go 😊.
We’re gonna use the almighty Rollup.Js to bundle our code and create a single index.js
file that’ll contain all our code.
This bundled index.js
file will contain everything, our code, the express library code or any other library code that we’re using.
Installing Rollup
Install these packages :-
-
rollup
-
@rollup/plugin-node-resolve
-
@rollup/plugin-json
-
@rollup/plugin-commonjs
Create a rollup.config.mjs
file in the root of your project and add this to it :-
import commonjs from "@rollup/plugin-commonjs"; import resolve from "@rollup/plugin-node-resolve"; import json from "@rollup/plugin-json"; export default { input: "src/index.js", output: { file: "dist/index.js", format: "cjs", }, plugins: [ resolve(), // Resolve modules from node_modules commonjs(), // Convert CommonJS modules to ES6 json(), // Handle JSON files ], };
Packaging the code 📦
Just run this command in your terminal :-
npx rollup -c
or you can install rollup globally using your fav package manager (me 💗 pnpm
) and just run rollup -c
in your terminal.
That should create one (just one ☝🏻) big filesize index.js
inside the dist
folder.
Creating Single Executable 📦
I have NodeJs v22 installed on my Windows PC.
Let’s quickly go through the following steps and get our hands on that single executable file 😎 :-
-
Create a folder called
blob
in the root of your project. (just to keep things tidy 🤷🏻♂️) -
Create a file called
sea-config.json
in the root of your project and add this to it :-{ "main": "./dist/index.js", "output": "./blob/sea-prep.blob" }
-
Copy NodeJs executable file to this project’s root with this command :-
node -e "require('fs').copyFileSync(process.execPath, 'app.exe')"
That’s right, we’re copying the actual NodeJs executable installed on your system and we’ll “inject” our code into it.
-
Optional Step on Windows
This step is not worth it if you don’t have a liscense for whatever desktop app you’re working on.
So …, remove the signature from this copied binary file using the signtool by runningsigntool remove /s app.exe
-
Inject the blob into the binary :-
npx postject app.exe NODE_SEA_BLOB ./blob/sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
-
Another Optional Step on Windows
Again, this step is not worth it if you don’t have a liscense for whatever desktop app you’re working on.
So …, sign the app using the signtool by runningsigntool sign /fd SHA256 app.exe
And that’s it 🥳🥳🥳. You should have a single executable file in the root of your project called app.exe
. Use it however you like.
Thanks 🤗 for reading all the way till down here. Please consider subscribing(click) (tap) and check out some other stuff I wrote below 👇🏻