{"id":18486788,"url":"https://github.com/yao-pkg/pkg","last_synced_at":"2025-04-08T19:33:55.074Z","repository":{"id":198009828,"uuid":"699692402","full_name":"yao-pkg/pkg","owner":"yao-pkg","description":"Package your Node.js project into an executable","archived":false,"fork":true,"pushed_at":"2025-03-20T07:58:12.000Z","size":27933,"stargazers_count":551,"open_issues_count":22,"forks_count":29,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-08T11:41:47.582Z","etag":null,"topics":["hacktoberfest","nodejs","pkg","single-executable"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@yao-pkg/pkg","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"vercel/pkg","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yao-pkg.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-10-03T06:33:58.000Z","updated_at":"2025-04-08T07:17:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"a2533f68-1cbe-447b-a394-051032837500","html_url":"https://github.com/yao-pkg/pkg","commit_stats":null,"previous_names":["yao-pkg/pkg"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yao-pkg%2Fpkg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yao-pkg%2Fpkg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yao-pkg%2Fpkg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yao-pkg%2Fpkg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yao-pkg","download_url":"https://codeload.github.com/yao-pkg/pkg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247912805,"owners_count":21017048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","nodejs","pkg","single-executable"],"created_at":"2024-11-06T12:49:49.379Z","updated_at":"2025-04-08T19:33:55.066Z","avatar_url":"https://github.com/yao-pkg.png","language":"JavaScript","readme":"[![Build Status](https://github.com/yao-pkg/pkg/actions/workflows/ci.yml/badge.svg)](https://github.com/yao-pkg/pkg/actions/workflows/ci.yml)\n\nThis command line interface enables you to package your Node.js project into an executable that can be run even on devices without Node.js installed.\n\n## Use Cases\n\n- Make a commercial version of your application without sources\n- Make a demo/evaluation/trial version of your app without sources\n- Instantly make executables for other platforms (cross-compilation)\n- Make some kind of self-extracting archive or installer\n- No need to install Node.js and npm to run the packaged application\n- No need to download hundreds of files via `npm install` to deploy\n  your application. Deploy it as a single file\n- Put your assets inside the executable to make it even more portable\n- Test your app against new Node.js version without installing it\n\n## Usage\n\n```sh\nnpm install -g @yao-pkg/pkg\n```\n\nAfter installing it, run `pkg --help` without arguments to see list of options:\n\n```console\n  pkg [options] \u003cinput\u003e\n\n  Options:\n\n    -h, --help           output usage information\n    -v, --version        output pkg version\n    -t, --targets        comma-separated list of targets (see examples)\n    -c, --config         package.json or any json file with top-level config\n    --options            bake v8 options into executable to run with them on\n    -o, --output         output file name or template for several files\n    --out-path           path to save output one or more executables\n    -d, --debug          show more information during packaging process [off]\n    -b, --build          don't download prebuilt base binaries, build them\n    --public             speed up and disclose the sources of top-level project\n    --public-packages    force specified packages to be considered public\n    --no-bytecode        skip bytecode generation and include source files as plain js\n    --no-native-build    skip native addons build\n    --no-dict            comma-separated list of packages names to ignore dictionaries. Use --no-dict * to disable all dictionaries\n    -C, --compress       [default=None] compression algorithm = Brotli or GZip\n    --sea                (Experimental) compile give file using node's SEA feature. Requires node v20.0.0 or higher and only single file is supported\n\n  Examples:\n\n  – Makes executables for Linux, macOS and Windows\n    $ pkg index.js\n  – Takes package.json from cwd and follows 'bin' entry\n    $ pkg .\n  – Makes executable for particular target machine\n    $ pkg -t node14-win-arm64 index.js\n  – Makes executables for target machines of your choice\n    $ pkg -t node16-linux,node18-linux,node18-win index.js\n  – Bakes '--expose-gc' and '--max-heap-size=34' into executable\n    $ pkg --options \"expose-gc,max-heap-size=34\" index.js\n  – Consider packageA and packageB to be public\n    $ pkg --public-packages \"packageA,packageB\" index.js\n  – Consider all packages to be public\n    $ pkg --public-packages \"*\" index.js\n  – Bakes '--expose-gc' into executable\n    $ pkg --options expose-gc index.js\n  – reduce size of the data packed inside the executable with GZip\n    $ pkg --compress GZip index.js\n  – compile the file using node's SEA feature. Creates executables for Linux, macOS and Windows\n    $ pkg --sea index.js\n```\n\nThe entrypoint of your project is a mandatory CLI argument. It may be:\n\n- Path to entry file. Suppose it is `/path/app.js`, then\n  packaged app will work the same way as `node /path/app.js`\n- Path to `package.json`. `Pkg` will follow `bin` property of\n  the specified `package.json` and use it as entry file.\n- Path to directory. `Pkg` will look for `package.json` in\n  the specified directory. See above.\n\n### Targets\n\n`pkg` can generate executables for several target machines at a\ntime. You can specify a comma-separated list of targets via `--targets`\noption. A canonical target consists of 3 elements, separated by\ndashes, for example `node18-macos-x64` or `node14-linux-arm64`:\n\n- **nodeRange** (node8), node10, node12, node14, node16 or latest\n- **platform** alpine, linux, linuxstatic, win, macos, (freebsd)\n- **arch** x64, arm64, (armv6, armv7)\n\n(element) is unsupported, but you may try to compile yourself.\n\nYou may omit any element (and specify just `node14` for example).\nThe omitted elements will be taken from current platform or\nsystem-wide Node.js installation (its version and arch).\nThere is also an alias `host`, that means that all 3 elements\nare taken from current platform/Node.js. By default targets are\n`linux,macos,win` for current Node.js version and arch.\n\nIf you want to generate executable for different architectures,\nnote that by default `pkg` has to run the executable of the\n**target** arch to generate bytecodes:\n\n- Linux: configure binfmt with [QEMU](https://wiki.debian.org/QemuUserEmulation).\n- macOS: possible to build `x64` on `arm64` with `Rosetta 2` but not opposite.\n- Windows: possible to build `x64` on `arm64` with `x64 emulation` but not opposite.\n- or, disable bytecode generation with `--no-bytecode --public-packages \"*\" --public`.\n\n`macos-arm64` is experimental. Be careful about the [mandatory code signing requirement](https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-universal-apps-release-notes).\nThe final executable has to be signed (ad-hoc signature is sufficient) with `codesign`\nutility of macOS (or `ldid` utility on Linux). Otherwise, the executable will be killed\nby kernel and the end-user has no way to permit it to run at all. `pkg` tries to ad-hoc\nsign the final executable. If necessary, you can replace this signature with your own\ntrusted Apple Developer ID.\n\nTo be able to generate executables for all supported architectures and platforms, run\n`pkg` on a Linux host with binfmt (`QEMU` emulation) configured and `ldid` installed.\n\n### Config\n\nDuring packaging process `pkg` parses your sources, detects\ncalls to `require`, traverses the dependencies of your project\nand includes them into executable. In most cases you\ndon't need to specify anything manually.\n\nHowever your code may have `require(variable)` calls (so called non-literal\nargument to `require`) or use non-javascript files (for\nexample views, css, images etc).\n\n```js\nrequire('./build/' + cmd + '.js');\npath.join(__dirname, 'views/' + viewName);\n```\n\nSuch cases are not handled by `pkg`. So you must specify the\nfiles - scripts and assets - manually in `pkg` property of\nyour `package.json` file.\n\n```json\n  \"pkg\": {\n    \"scripts\": \"build/**/*.js\",\n    \"assets\": \"views/**/*\",\n    \"targets\": [ \"node14-linux-arm64\" ],\n    \"outputPath\": \"dist\"\n  }\n```\n\nThe above example will include everything in `assets/` and\nevery .js file in `build/`, build only for `node14-linux-arm64`,\nand place the executable inside `dist/`.\n\nYou may also specify arrays of globs:\n\n```\n    \"assets\": [ \"assets/**/*\", \"images/**/*\" ]\n```\n\nJust be sure to call `pkg package.json` or `pkg .` to make\nuse of `package.json` configuration.\n\n### Scripts\n\n`scripts` is a [glob](https://github.com/SuperchupuDev/tinyglobby)\nor list of globs. Files specified as `scripts` will be compiled\nusing `v8::ScriptCompiler` and placed into executable without\nsources. They must conform to the JS standards of those Node.js versions\nyou target (see [Targets](#targets)), i.e. be already transpiled.\n\n### Assets\n\n`assets` is a [glob](https://github.com/SuperchupuDev/tinyglobby)\nor list of globs. Files specified as `assets` will be packaged\ninto executable as raw content without modifications. Javascript\nfiles may also be specified as `assets`. Their sources will\nnot be stripped as it improves execution performance of the\nfiles and simplifies debugging.\n\nSee also\n[Detecting assets in source code](#detecting-assets-in-source-code) and\n[Snapshot filesystem](#snapshot-filesystem).\n\n### Ignore files\n\n`ignore` is a list of globs. Files matching the paths specified as `ignore`\nwill be excluded from the final executable.\n\nThis is useful when you want to exclude some files from the final executable,\nlike tests, documentation or build files that could have been included by a dependency.\n\n```json\n  \"pkg\": {\n    \"ignore\": [ \"**/*/dependency-name/build.c\" ]\n  }\n```\n\nTo see if you have unwanted files in your executable, read the [Exploring virtual file system embedded in debug mode](#exploring-virtual-file-system-embedded-in-debug-mode) section.\n\n### Options\n\nNode.js application can be called with runtime options\n(belonging to Node.js or V8). To list them type `node --help` or `node --v8-options`.\n\nYou can \"bake\" these runtime options into packaged application. The app will always run with the options\nturned on. Just remove `--` from option name.\n\nYou can specify multiple options by joining them in a single string, comma (`,`) separated:\n\n```sh\npkg app.js --options expose-gc\npkg app.js --options max_old_space_size=4096\npkg app.js --options max-old-space-size=1024,tls-min-v1.0,expose-gc\n```\n\n### Output\n\nYou may specify `--output` if you create only one executable\nor `--out-path` to place executables for multiple targets.\n\n### Debug\n\nPass `--debug` to `pkg` to get a log of packaging process.\nIf you have issues with some particular file (seems not packaged\ninto executable), it may be useful to look through the log.\n\nIn order to get more detailed logs on startup, after you packaged your application using `--debug`, you can start your application with the environment variable `DEBUG_PKG` set to `1` or `2` if you want more verbose debugging. This will load `prelude/diagnostic.js` that will print the snapshot tree and the symlink table, when set to `2` it will also mock `fs` in order to print logs when a method is called.\n\nThis is useful to see what's included in your bundle and detect possible missing files or large files that could be removed from it in order to reduce the size of the executable.\n\nYou can also use `SIZE_LIMIT_PKG` and `FOLDER_LIMIT_PKG` to print files/folders that are larger than the specified size limit (in bytes). By default, the size limit is set to 5MB for files and 10MB for folders.\n\n### Bytecode (reproducibility)\n\nBy default, your source code is precompiled to v8 bytecode before being written\nto the output file. To disable this feature, pass `--no-bytecode` to `pkg`.\n\n#### Why would you want to do this?\n\nIf you need a reproducible build\nprocess where your executable hashes (e.g. md5, sha1, sha256, etc.) are the\nsame value between builds. Because compiling bytecode is not deterministic\n(see [here](https://ui.adsabs.harvard.edu/abs/2019arXiv191003478C/abstract) or\n[here](https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775)) it\nresults in executables with differing hashed values. Disabling bytecode\ncompilation allows a given input to always have the same output.\n\n#### Why would you NOT want to do this?\n\nWhile compiling to bytecode does not make your source code 100% secure, it does\nadd a small layer of security/privacy/obscurity to your source code. Turning\noff bytecode compilation causes the raw source code to be written directly to\nthe executable file. If you're on \\*nix machine and would like an example, run\n`pkg` with the `--no-bytecode` flag, and use the GNU strings tool on the\noutput. You then should be able to grep your source code.\n\n#### Other considerations\n\nSpecifying `--no-bytecode` will fail if there are any packages in your project that aren't explicitly marked\nas public by the `license` in their `package.json`.\nBy default, `pkg` will check the license of each package and make sure that stuff that isn't meant for the public will\nonly be included as bytecode.\n\nIf you do require building pkg binaries for other architectures and/or depend on a package with a broken\n`license` in its `package.json`, you can override this behaviour by either explicitly whitelisting packages to be public\nusing `--public-packages \"packageA,packageB\"` or setting all packages to public using `--public-packages \"*\"`\n\n### Build\n\n`pkg` has so called \"base binaries\" - they are actually same\n`node` executables but with some patches applied. They are\nused as a base for every executable `pkg` creates. `pkg`\ndownloads precompiled base binaries before packaging your\napplication. If you prefer to compile base binaries from\nsource instead of downloading them, you may pass `--build`\noption to `pkg`. First ensure your computer meets the\nrequirements to compile original Node.js:\n[BUILDING.md](https://github.com/nodejs/node/blob/HEAD/BUILDING.md)\n\nSee [pkg-fetch](https://github.com/yao-pkg/pkg-fetch) for more info.\n\n### Compression\n\nPass `--compress Brotli` or `--compress GZip` to `pkg` to compress further the content of the files store in the exectable.\n\nThis option can reduce the size of the embedded file system by up to 60%.\n\nThe startup time of the application might be reduced slightly.\n\n`-C` can be used as a shortcut for `--compress`.\n\n### Environment\n\nAll pkg-cache [environment vars](https://github.com/yao-pkg/pkg-fetch#environment), plus:\n\n| Var              | Description                                                                                                                                                          |\n| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `CHDIR`          | Override process `chdir`                                                                                                                                             |\n| `PKG_STRICT_VER` | Turn on some assertion in the walker code to assert that each file content/state that we appending to the virtual file system applies to a real file, not a symlink. |\n| `PKG_EXECPATH`   | Used internally by `pkg`, do not override                                                                                                                            |\n\nExamples\n\n```bash\n# 1 - Using export\nexport PKG_CACHE_PATH=/my/cache\npkg app.js\n\n# 2 - Passing it before the script\nPKG_CACHE_PATH=/my/cache pkg app.js\n```\n\n## Usage of packaged app\n\nCommand line call to packaged app `./app a b` is equivalent\nto `node app.js a b`\n\n## Snapshot filesystem\n\nDuring packaging process `pkg` collects project files and places\nthem into executable. It is called a snapshot. At run time the\npackaged application has access to snapshot filesystem where all\nthat files reside.\n\nPackaged files have `/snapshot/` prefix in their paths (or\n`C:\\snapshot\\` in Windows). If you used `pkg /path/app.js` command line,\nthen `__filename` value will be likely `/snapshot/path/app.js`\nat run time. `__dirname` will be `/snapshot/path` as well. Here is\nthe comparison table of path-related values:\n\n| value                         | with `node`     | packaged                 | comments                       |\n| ----------------------------- | --------------- | ------------------------ | ------------------------------ |\n| \\_\\_filename                  | /project/app.js | /snapshot/project/app.js |\n| \\_\\_dirname                   | /project        | /snapshot/project        |\n| process.cwd()                 | /project        | /deploy                  | suppose the app is called ...  |\n| process.execPath              | /usr/bin/nodejs | /deploy/app-x64          | `app-x64` and run in `/deploy` |\n| process.argv[0]               | /usr/bin/nodejs | /deploy/app-x64          |\n| process.argv[1]               | /project/app.js | /snapshot/project/app.js |\n| process.pkg.entrypoint        | undefined       | /snapshot/project/app.js |\n| process.pkg.defaultEntrypoint | undefined       | /snapshot/project/app.js |\n| require.main.filename         | /project/app.js | /snapshot/project/app.js |\n\nHence, in order to make use of a file collected at packaging\ntime (`require` a javascript file or serve an asset) you should\ntake `__filename`, `__dirname`, `process.pkg.defaultEntrypoint`\nor `require.main.filename` as a base for your path calculations.\nFor javascript files you can just `require` or `require.resolve`\nbecause they use current `__dirname` by default. For assets use\n`path.join(__dirname, '../path/to/asset')`. Learn more about\n`path.join` in\n[Detecting assets in source code](#detecting-assets-in-source-code).\n\nOn the other hand, in order to access real file system at run time\n(pick up a user's external javascript plugin, json configuration or\neven get a list of user's directory) you should take `process.cwd()`\nor `path.dirname(process.execPath)`.\n\n## Detecting assets in source code\n\nWhen `pkg` encounters `path.join(__dirname, '../path/to/asset')`,\nit automatically packages the file specified as an asset. See\n[Assets](#assets). Pay attention that `path.join` must have two\narguments and the last one must be a string literal.\n\nThis way you may even avoid creating `pkg` config for your project.\n\n## Native addons\n\nNative addons (`.node` files) use is supported. When `pkg` encounters\na `.node` file in a `require` call, it will package this like an asset.\nIn some cases (like with the `bindings` package), the module path is generated\ndynamically and `pkg` won't be able to detect it. In this case, you should\nadd the `.node` file directly in the `assets` field in `package.json`.\n\nThe way Node.js requires native addon is different from a classic JS\nfile. It needs to have a file on disk to load it, but `pkg` only generates\none file. To circumvent this, `pkg` will extract native addon files to\n`$HOME/.cache/pkg/`. These files will stay on the disk after the process has\nexited and will be used again on the next process launch.\n\nWhen a package, that contains a native module, is being installed,\nthe native module is compiled against current system-wide Node.js\nversion. Then, when you compile your project with `pkg`, pay attention\nto `--target` option. You should specify the same Node.js version\nas your system-wide Node.js to make compiled executable compatible\nwith `.node` files.\n\nNote that fully static Node binaries are not capable of loading native\nbindings, so you may not use Node bindings with `linuxstatic`.\n\n## API\n\n`const { exec } = require('pkg')`\n\n`exec(args)` takes an array of command line arguments and returns\na promise. For example:\n\n```js\nawait exec(['app.js', '--target', 'host', '--output', 'app.exe']);\n// do something with app.exe, run, test, upload, deploy, etc\n```\n\n## Use custom Node.js binary\n\nIn case you want to use custom node binary, you can set `PKG_NODE_PATH` environment variable to the path of the node binary you want to use and `pkg` will use it instead of the default one.\n\n```bash\nPKG_NODE_PATH=/path/to/node pkg app.js\n```\n\n## Troubleshooting\n\n### Error: Error [ERR_REQUIRE_ESM]: require() of ES Module\n\nThis error is tracked by issue [#16](https://github.com/yao-pkg/pkg/issues/16#issuecomment-1945486658). Follow the link in oder to find a workaround.\n\nIn most cases adding `--options experimental-require-module` to `pkg` command line will solve the issue.\n\n\u003e [!NOTE]\n\u003e This option is not needed anymore starting from NodeJS v22.12.0\n\n### Error: Cannot find module XXX (when using `child_process`)\n\nWhen using `child_process` methods to run a new process pkg by default will invoke it using NodeJS runtime that is built into the executable. This means that if you are trying to spawn the packaged app itself you will get above error. In order to avoid this you must set `PKG_EXECPATH` env set to `\"\"`:\n\n```js\nconst { spawn } = require('child_process');\n\nconst child = spawn(process.execPath, [process.argv[1]], {\n  env: {\n    ...process.env,\n    PKG_EXECPATH: '',\n  },\n});\n```\n\nMore info [here](https://github.com/yao-pkg/pkg/pull/90)\n\n### Error: Cannot execute binaray from snapshot\n\nBinaries must be extracted from snapshot in order to be executed. In order to do this you can use this approach:\n\n```js\nconst cp = require('child_process');\nconst fs = require('fs');\nconst { pipeline } = require('stream/promises');\n\nlet ffmpeg = require('@ffmpeg-installer/ffmpeg').path;\n\nconst loadPlugin = async () =\u003e {\n  if (process.pkg) {\n    // copy ffmpeg to the current directory\n    const file = fs.createWriteStream('ffmpeg');\n    await pipeline(fs.createReadStream(ffmpeg), file);\n\n    fs.chmodSync('ffmpeg', 0o755);\n    console.log('ffmpeg copied to the current directory');\n    ffmpeg = './ffmpeg';\n  }\n\n  cp.execSync(ffmpeg);\n};\n\nloadPlugin();\n```\n\n### Error: ENOENT: no such file or directory, uv_chdir\n\nThis error can be caused by deleting the directory the application is\nrun from. Or, generally, deleting `process.cwd()` directory when the\napplication is running.\n\n### Error: ERR_INSPECTOR_NOT_AVAILABLE\n\nThis error can be caused by using `NODE_OPTIONS` variable to force to\nrun `node` with the debug mode enabled. Debugging options are disallowed\n, as **pkg** executables are usually used for production environments.\nIf you do need to use inspector, you can [build a debuggable Node.js](https://github.com/vercel/pkg/issues/93#issuecomment-301210543) yourself.\n\n### Error: require(...).internalModuleStat is not a function\n\nThis error can be caused by using `NODE_OPTIONS` variable with some\nbootstrap or `node` options causing conflicts with **pkg**. Some\nIDEs, such as **VS Code**, may add this env variable automatically.\n\nYou could check on **Unix systems** (Linux/macOS) in `bash`:\n\n```bash\nprintenv | grep NODE\n```\n\n## Advanced\n\n### Exploring virtual file system embedded in debug mode\n\nWhen you are using the `--debug` flag when building your executable,\n`pkg` add the ability to display the content of the virtual file system\nand the symlink table on the console, when the application starts,\nproviding that the environement variable DEBUG_PKG is set.\nThis feature can be useful to inspect if symlinks are correctly handled,\nand check that all the required files for your application are properly\nincorporated to the final executable.\n\n    pkg --debug app.js -o output\n    DEBUG_PKG=1 output\n\nor\n\n    C:\\\u003e pkg --debug app.js -o output.exe\n    C:\\\u003e set DEBUG_PKG=1\n    C:\\\u003e output.exe\n\nNote: make sure not to use --debug flag in production.\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyao-pkg%2Fpkg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyao-pkg%2Fpkg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyao-pkg%2Fpkg/lists"}