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. Inject the JavaScript file into the copied binary by running `postject` with 43 the following options: 44 45 * `hello` - The name of the copy of the `node` executable created in step 2. 46 * `NODE_JS_CODE` - The name of the resource / note / section in the binary 47 where the contents of the JavaScript file will be stored. 48 * `hello.js` - The name of the JavaScript file created in step 1. 49 * `--sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2` - The 50 [fuse][] used by the Node.js project to detect if a file has been injected. 51 * `--macho-segment-name NODE_JS` (only needed on macOS) - The name of the 52 segment in the binary where the contents of the JavaScript file will be 53 stored. 54 55 To summarize, here is the required command for each platform: 56 57 * On systems other than macOS: 58 ```console 59 $ npx postject hello NODE_JS_CODE hello.js \ 60 --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 61 ``` 62 63 * On macOS: 64 ```console 65 $ npx postject hello NODE_JS_CODE hello.js \ 66 --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \ 67 --macho-segment-name NODE_JS 68 ``` 69 704. Run the binary: 71 ```console 72 $ ./hello world 73 Hello, world! 74 ``` 75 76## Notes 77 78### `require(id)` in the injected module is not file based 79 80`require()` in the injected module is not the same as the [`require()`][] 81available to modules that are not injected. It also does not have any of the 82properties that non-injected [`require()`][] has except [`require.main`][]. It 83can only be used to load built-in modules. Attempting to load a module that can 84only be found in the file system will throw an error. 85 86Instead of relying on a file based `require()`, users can bundle their 87application into a standalone JavaScript file to inject into the executable. 88This also ensures a more deterministic dependency graph. 89 90However, if a file based `require()` is still needed, that can also be achieved: 91 92```js 93const { createRequire } = require('node:module'); 94require = createRequire(__filename); 95``` 96 97### `__filename` and `module.filename` in the injected module 98 99The values of `__filename` and `module.filename` in the injected module are 100equal to [`process.execPath`][]. 101 102### `__dirname` in the injected module 103 104The value of `__dirname` in the injected module is equal to the directory name 105of [`process.execPath`][]. 106 107### Single executable application creation process 108 109A tool aiming to create a single executable Node.js application must 110inject the contents of a JavaScript file into: 111 112* a resource named `NODE_JS_CODE` if the `node` binary is a [PE][] file 113* a section named `NODE_JS_CODE` in the `NODE_JS` segment if the `node` binary 114 is a [Mach-O][] file 115* a note named `NODE_JS_CODE` if the `node` binary is an [ELF][] file 116 117Search the binary for the 118`NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0` [fuse][] string and flip the 119last character to `1` to indicate that a resource has been injected. 120 121### Platform support 122 123Single-executable support is tested regularly on CI only on the following 124platforms: 125 126* Windows 127* macOS 128* Linux (AMD64 only) 129 130This is due to a lack of better tools to generate single-executables that can be 131used to test this feature on other platforms. 132 133Suggestions for other resource injection tools/workflows are welcomed. Please 134start a discussion at <https://github.com/nodejs/single-executable/discussions> 135to help us document them. 136 137[CommonJS]: modules.md#modules-commonjs-modules 138[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 139[Mach-O]: https://en.wikipedia.org/wiki/Mach-O 140[PE]: https://en.wikipedia.org/wiki/Portable_Executable 141[`process.execPath`]: process.md#processexecpath 142[`require()`]: modules.md#requireid 143[`require.main`]: modules.md#accessing-the-main-module 144[fuse]: https://www.electronjs.org/docs/latest/tutorial/fuses 145[postject]: https://github.com/nodejs/postject 146[single executable applications]: https://github.com/nodejs/single-executable 147