git ssb


cel-desktop / ssb-pkg

cel committed Allow fetching blobs over httpsLatest: ca90b5c on 5/9/2021, 1:41:22 AM


Single-command Node.js binary compiler and installer generator for Secure Scuttlebutt (SSB). Based on pkg by Zeit.

This command line interface enables you to package your Node.js project into an installer that runs on SSB and generate an executable that can be run even on devices without Node.js installed.

Use Cases


Install using ssb-npm:

ssb-npm install -g ssb-pkg@1.2.0 --branch %YKEwg4gwXzb3PgPue/wfLS4U9ezJjBoPhpXEEQioQjA=.sha256

Don't have ssb-npm? Install the binary build of ssb-pkg, built with ssb-pkg itself:

# Installs ssb-pkg v1.2.0 for linux-{x64,armv7,arm64,x86} and macos-x64
curl -s 'http://localhost:8989/blobs/get/&VCC6mfReR0c4AkHiGOftaRwuUGAUHyh18nmlyAGL9G8=.sha256' | sh

After installing it, run ssb-pkg --help without arguments to see list of options.

The entrypoint of your project is a mandatory CLI argument. It may be:


ssb-pkg can generate an installer for multiple target machines. You can specify a comma-separated list of targets via --targets
option. A canonical target consists of 3 elements, separated by dashes, for example node6-macos-x64 or node4-linux-armv6:

You may omit any element (and specify just node6 for example). The omitted elements will be taken from current platform or system-wide Node.js installation (its version and arch). There is also an alias host, that means that all 3 elements are taken from current platform/Node.js. By default targets are linux,macos,win for current Node.js version and arch.


During packaging process ssb-pkg parses your sources, detects calls to require, traverses the dependencies of your project and includes them into executable. In most cases you don't need to specify anything manually. However your code may have require(variable) calls (so called non-literal argument to require) or use non-javascript files (for example views, css, images etc).

  require('./build/' + cmd + '.js')
  path.join(__dirname, 'views/' + viewName)

Such cases are not handled by ssb-pkg. So you must specify the files - scripts and assets - manually in pkg property of your package.json file.

  "pkg": {
    "scripts": "build/**/*.js",
    "assets": "views/**/*"

You may also specify arrays of globs:

    "assets": [ "assets/**/*", "images/**/*" ]

Just be sure to call ssb-pkg package.json or ssb-pkg . to make use of scripts and assets entries.


scripts is a glob
or list of globs. Files specified as scripts will be compiled using v8::ScriptCompiler and placed into executable without sources. They must conform to the JS standards of those Node.js versions you target (see Targets), i.e. be already transpiled.


assets is a glob
or list of globs. Files specified as assets will be packaged into executable as raw content without modifications. Javascript files may also be specified as assets. Their sources will not be stripped as it improves execution performance of the files and simplifies debugging.

See also Detecting assets in source code and Snapshot filesystem.

Blob Assets

blobAssets is a glob
or list of globs, or object mapping targets to lists of globs. Files specified in blobAssets will be packaged into the executable via SSB blobs fetched during install, rather than being included in the main payload blob (snapshot) with the rest of the assets and scripts. This allows the payload size to be decreased by factoring out large infrequently changed files. If blobAssets is organized by target, each set of files is only added during install time if its target name matches the system platform and architecture or is "*"; this is to allow for packing additional binaries so that they are only fetched for the systems that need them, and the payload blob can be reused on all the systems.


    "blobAssets": {
      "linux-x64": [
      "linux-arm": [
      "darwin-x64": [

Special handling of modules for Blob Assets

Since sodium-native is commonly required for SSB Node.js applications, ssb-pkg detects it in the dependency tree and automatically adds blobAssets entries for the module's shared libraries corresponding to the current targets.


Node.js application can be called with runtime options (belonging to Node.js or V8). To list them type node --help or node --v8-options. You can "bake" these runtime options into packaged application. The app will always run with the options turned on. Just remove -- from option name.

ssb-pkg app.js --options expose-gc
ssb-pkg app.js --options max_old_space_size=4096


You may specify --output to place the generated installer; otherwise a location is picked for you.


Pass --debug to ssb-pkg to get a log of packaging process. If you have issues with some particular file (seems not packaged into executable), it may be useful to look through the log.


pkg/ssb-pkg has so called "base binaries" - they are actually same node executables but with some patches applied. They are used as a base for every executable ssb-pkg creates. ssb-pkg
fetches precompiled base binaries via SSB before packaging your application. If you prefer to compile base binaries from source instead of downloading them, you may pass --build
option to ssb-pkg. First ensure your computer meets the requirements to compile original Node.js:

Usage of packaged app

Command line call to packaged app ./app a b is equivalent to node app.js a b

Snapshot filesystem

During packaging process ssb-pkg collects project files and places them into executable. It is called a snapshot. At run time the packaged application has access to snapshot filesystem where all that files reside.

Packaged files have /snapshot/ prefix in their paths (or C:\snapshot\ in Windows). If you used ssb-pkg /path/app.js command line, then __filename value will be likely /snapshot/path/app.js
at run time. __dirname will be /snapshot/path as well. Here is the comparison table of path-related values:

value with node packaged comments
__filename /project/app.js /snapshot/project/app.js
__dirname /project /snapshot/project
process.cwd() /project /deploy suppose the app is called ...
process.execPath /usr/bin/nodejs /deploy/app-x64 app-x64 and run in /deploy
process.argv[0] /usr/bin/nodejs /deploy/app-x64
process.argv[1] /project/app.js /snapshot/project/app.js
process.pkg.entrypoint undefined /snapshot/project/app.js
process.pkg.defaultEntrypoint undefined /snapshot/project/app.js
require.main.filename /project/app.js /snapshot/project/app.js

Hence, in order to make use of a file collected at packaging time (require a javascript file or serve an asset) you should take __filename, __dirname, process.pkg.defaultEntrypoint
or require.main.filename as a base for your path calculations. For javascript files you can just require or require.resolve
because they use current __dirname by default. For assets use path.join(__dirname, '../path/to/asset'). Learn more about path.join in Detecting assets in source code.

On the other hand, in order to access real file system at run time (pick up a user's external javascript plugin, json configuration or even get a list of user's directory) you should take process.cwd()
or path.dirname(process.execPath).

Detecting assets in source code

When ssb-pkg encounters path.join(__dirname, '../path/to/asset'), it automatically packages the file specified as an asset. See Assets. Pay attention that path.join must have two arguments and the last one must be a string literal.

This way you may even avoid creating pkg config for your project.

Native addons

Native addons (.node files) use is supported. When ssb-pkg encounters a .node file in a require call, it will package this like an asset. In some cases (like with the bindings package), the module path is generated dynamicaly and ssb-pkg won't be able to detect it. In this case, you should add the .node file(s) directly in the assets and/or blobAssets fields in package.json.

The way NodeJS requires native addon is different from a classic JS file. It needs to have a file on disk to load it but ssb-pkg only generate one file. To circumvent this, ssb-pkg will create a file on the disk. These files will stay on the disk after the process has exited and will be used again on the next process launch. They are stored under ~/.cache/ssb-pkg/.

When a package, that contains a native module, is being installed, the native module is compiled against current system-wide Node.js version. Then, when you compile your project with ssb-pkg, pay attention to --target option. You should specify the same Node.js version as your system-wide Node.js to make compiled executable compatible with .node files.

If a native module package contains multiple .node files for different platforms/architectures/Node.js versions (e.g. prebuilds), you may specify them with the blobAssets config option as described in Blob Assets. For some packages this is done automatically, as described in Special handling of modules for Blob Assets.


const { exec } = require('ssb-pkg')

exec(args) takes an array of command line arguments and returns a promise. For example:

await exec([ 'app.js', '--target', 'host', '--output', '' ])
// do something with, run, test, upload, deploy, etc


Error: ENOENT: no such file or directory, uv_chdir

This error can be caused by deleting the directory the application is run from. Or, generally, deleting process.cwd() directory when the application is running.


ssb-pkg doesn't support Windows yet. If you can help with this, please open an issue.

Built with git-ssb-web