HakobuHakobu

Runtime Support Matrix

Complete feature matrix for Hakobu-packaged binaries.

This page documents what works at runtime inside a Hakobu-packaged executable, including module system support, runtime APIs, native addons, and known limitations.

Node Version

Hakobu targets Node 24.x LTS exclusively.

PropertyValue
Node versionv24.14.0
V8 ABI137
Base binary formatPatched Node with snapshot filesystem support

Older Node lines (18, 20, 22) are not supported. Hakobu only ships base binaries for Node 24.

Supported Targets

Published Base Binaries

TargetTierStatus
linux-x641Available
linux-arm641Available
win-x641Available
macos-arm641Available
macos-x642Available
linuxstatic-x642Available
win-arm642Available (requires windows-11-arm runner)

Blocked Targets

TargetReason
linuxstatic-arm64muslcc GCC too old for Node 24's C++20 requirements
alpine-*Not yet built (would be similar to linuxstatic)

Use hakobu targets to see which base binaries are cached locally and which are available remotely.

ESM Support

FeatureStatusNotes
"type": "module" in package.jsonFull support
.mjs filesFull support
Static importFull support
Dynamic import()SupportedStatic string paths only
import.meta.urlFull supportReturns file:///snapshot/... URL
package.json "exports" mapFull supportMain entry + subpath exports
package.json "imports" map (#specifiers)Supported
Import conditions: import, node, defaultFull support

CJS Support

FeatureStatusNotes
require()Full support
require.resolve()Full support
__dirname / __filenameAvailablePoint to snapshot paths
module.exports / exportsFull support
.cjs filesFull support
require('./data.json')Full support

Mixed Module Support

ScenarioStatus
ESM entry with createRequire() for CJS dependenciesWorks
CJS subpackage inside ESM root (via nested "type": "commonjs")Works
.mjs in CJS package / .cjs in ESM packageWorks

Child Processes

FeatureStatusNotes
child_process.spawn() / spawnSync()Works
child_process.fork() with IPCWorks
child_process.exec() / execSync()Works
process.execPathWorksPoints to the packaged binary
Environment inheritanceWorks
Custom stdio arraysWorks

process.execPath -e "code" does not work from inside a packaged app. The prelude interprets -e as a module path. Use script files instead.

Worker Threads

FeatureStatusNotes
new Worker(path, { workerData })Works
parentPort.postMessage() / worker.on('message')Works
isMainThreadWorksCorrect in both main and worker contexts

Native Addons

Native .node files are detected during analysis and included in the snapshot. At runtime, addons are extracted from the snapshot to a cache directory and loaded via process.dlopen.

BehaviorDetails
Detection.node files found during static analysis
Extraction path~/.hakobu/addons/{sha256}/{filename}.node
Extraction behaviorIdempotent and cache-friendly

Addon Cache Resolution

The cache directory is resolved in the following order:

PrioritySourceExample
1HAKOBU_ADDON_CACHE env var/opt/myapp/addon-cache
2PKG_NATIVE_CACHE_PATH env var (legacy compat)/opt/myapp/cache
3$HOME/.hakobu/addons (default)/home/user/.hakobu/addons
4os.tmpdir() (fallback when home is unavailable)/tmp/hakobu-addons/{hash}

This means packaged apps work correctly for service users (nobody, www-data) and in containers where $HOME may not exist.

Native addons must be compiled for the target platform before packaging. Cross-compilation of .node files is not handled by Hakobu.

External Artifacts

External binaries (browsers, helper tools, large data files) can be declared in the Hakobu config and resolved at runtime:

package.json
{
  "hakobu": {
    "externals": ["camoufox-browser"]
  }
}

Resolution order:

  1. HAKOBU_EXTERNAL_{NAME} environment variable (uppercase, dashes replaced with underscores)
  2. {execDir}/externals/{name}/ (relative to the executable)
  3. Pattern path (absolute or relative to cwd)

Assets

Non-code files (templates, data, config) can be included via the assets config:

package.json
{
  "hakobu": {
    "assets": ["templates/**", "config.yaml"]
  }
}

Assets are included in the snapshot and readable via fs.readFileSync() at runtime using __dirname-relative or import.meta.url-derived paths.

Bytecode Mode

Opt-in V8 bytecode compilation for CJS scripts:

hakobu ./my-app --bytecode --output ./dist/app
Input TypeBytecode compiled?
CJS scripts (.js, .cjs)Yes
ESM scripts (.mjs, type: "module")No -- source only
JSON filesNo -- included as content
Assets / native addonsNo -- included as content/extracted

--bytecode and --bundle cannot be combined (bundle produces ESM). Bytecode is V8 version-specific -- executables must run on the same V8 version they were compiled with.

Offline / Air-Gapped Packaging

Hakobu can package without network access when the required base binaries are already cached:

HAKOBU_OFFLINE=1 hakobu ./my-app --output ./dist/app

To pre-populate the cache on a machine with network access, run Hakobu once per target, then copy ~/.hakobu/cache/ to the air-gapped machine. The cache location is configurable via HAKOBU_CACHE_PATH.

Known Limitations

  1. Node 24 only -- no support for older Node lines.
  2. process.execPath -e not supported -- use script files for child eval.
  3. linuxstatic-arm64 blocked -- toolchain incompatibility with Node 24's C++20 requirements.
  4. Bytecode + bundle incompatible -- use one or the other, not both.

On this page