1# Single executable applications 2 3<!--introduced_in=v18.16.0--> 4 5<!-- YAML 6added: 7 - v19.7.0 8 - v18.16.0 9--> 10 11> Stability: 1 - Experimental: This feature is being designed and will change. 12 13<!-- source_link=src/node_sea.cc --> 14 15This feature allows the distribution of a Node.js application conveniently to a 16system that does not have Node.js installed. 17 18Node.js supports the creation of [single executable applications][] by allowing 19the injection of a JavaScript file into the `node` binary. During start up, the 20program checks if anything has been injected. If the script is found, it 21executes its contents. Otherwise Node.js operates as it normally does. 22 23The single executable application feature only supports running a single 24embedded [CommonJS][] file. 25 26A bundled JavaScript file can be turned into a single executable application 27with any tool which can inject resources into the `node` binary. 28 29Here are the steps for creating a single executable application using one such 30tool, [postject][]: 31 321. Create a JavaScript file: 33 ```console 34 $ echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js 35 ``` 36 372. Create a copy of the `node` executable and name it according to your needs: 38 ```console 39 $ cp $(command -v node) hello 40 ``` 41 423. Remove the signature of the binary: 43 44 * On macOS: 45 46 ```console 47 $ codesign --remove-signature hello 48 ``` 49 50 * On Windows (optional): 51 52 [signtool][] can be used from the installed [Windows SDK][]. If this step is 53 skipped, ignore any signature-related warning from postject. 54 55 ```console 56 $ signtool remove /s hello 57 ``` 58 594. Inject the JavaScript file into the copied binary by running `postject` with 60 the following options: 61 62 * `hello` - The name of the copy of the `node` executable created in step 2. 63 * `NODE_JS_CODE` - The name of the resource / note / section in the binary 64 where the contents of the JavaScript file will be stored. 65 * `hello.js` - The name of the JavaScript file created in step 1. 66 * `--sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2` - The 67 [fuse][] used by the Node.js project to detect if a file has been injected. 68 * `--macho-segment-name NODE_JS` (only needed on macOS) - The name of the 69 segment in the binary where the contents of the JavaScript file will be 70 stored. 71 72 To summarize, here is the required command for each platform: 73 74 * On systems other than macOS: 75 ```console 76 $ npx postject hello NODE_JS_CODE hello.js \ 77 --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 78 ``` 79 80 * On macOS: 81 ```console 82 $ npx postject hello NODE_JS_CODE hello.js \ 83 --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \ 84 --macho-segment-name NODE_JS 85 ``` 86 875. Sign the binary: 88 89 * On macOS: 90 91 ```console 92 $ codesign --sign - hello 93 ``` 94 95 * On Windows (optional): 96 97 A certificate needs to be present for this to work. However, the unsigned 98 binary would still be runnable. 99 100 ```console 101 $ signtool sign /fd SHA256 hello 102 ``` 103 1046. Run the binary: 105 ```console 106 $ ./hello world 107 Hello, world! 108 ``` 109 110## Notes 111 112### `require(id)` in the injected module is not file based 113 114`require()` in the injected module is not the same as the [`require()`][] 115available to modules that are not injected. It also does not have any of the 116properties that non-injected [`require()`][] has except [`require.main`][]. It 117can only be used to load built-in modules. Attempting to load a module that can 118only be found in the file system will throw an error. 119 120Instead of relying on a file based `require()`, users can bundle their 121application into a standalone JavaScript file to inject into the executable. 122This also ensures a more deterministic dependency graph. 123 124However, if a file based `require()` is still needed, that can also be achieved: 125 126```js 127const { createRequire } = require('node:module'); 128require = createRequire(__filename); 129``` 130 131### `__filename` and `module.filename` in the injected module 132 133The values of `__filename` and `module.filename` in the injected module are 134equal to [`process.execPath`][]. 135 136### `__dirname` in the injected module 137 138The value of `__dirname` in the injected module is equal to the directory name 139of [`process.execPath`][]. 140 141### Single executable application creation process 142 143A tool aiming to create a single executable Node.js application must 144inject the contents of a JavaScript file into: 145 146* a resource named `NODE_JS_CODE` if the `node` binary is a [PE][] file 147* a section named `NODE_JS_CODE` in the `NODE_JS` segment if the `node` binary 148 is a [Mach-O][] file 149* a note named `NODE_JS_CODE` if the `node` binary is an [ELF][] file 150 151Search the binary for the 152`NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0` [fuse][] string and flip the 153last character to `1` to indicate that a resource has been injected. 154 155### Platform support 156 157Single-executable support is tested regularly on CI only on the following 158platforms: 159 160* Windows 161* macOS 162* Linux (all distributions [supported by Node.js][] except Alpine and all 163 architectures [supported by Node.js][] except s390x and ppc64) 164 165This is due to a lack of better tools to generate single-executables that can be 166used to test this feature on other platforms. 167 168Suggestions for other resource injection tools/workflows are welcomed. Please 169start a discussion at <https://github.com/nodejs/single-executable/discussions> 170to help us document them. 171 172[CommonJS]: modules.md#modules-commonjs-modules 173[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 174[Mach-O]: https://en.wikipedia.org/wiki/Mach-O 175[PE]: https://en.wikipedia.org/wiki/Portable_Executable 176[Windows SDK]: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ 177[`process.execPath`]: process.md#processexecpath 178[`require()`]: modules.md#requireid 179[`require.main`]: modules.md#accessing-the-main-module 180[fuse]: https://www.electronjs.org/docs/latest/tutorial/fuses 181[postject]: https://github.com/nodejs/postject 182[signtool]: https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool 183[single executable applications]: https://github.com/nodejs/single-executable 184[supported by Node.js]: https://github.com/nodejs/node/blob/main/BUILDING.md#platform-list 185