HakobuHakobu

Native Mode

How Hakobu's default native packaging mode works.

Native mode is Hakobu's default packaging mode. It packages your JavaScript files directly from disk without any transformation step, preserving the file-by-file structure inside the snapshot filesystem.

hakobu ./my-project --output ./dist/app

When to Use Native Mode

Use native mode when your project is already plain JavaScript that Node.js can run directly. This is the primary path and the most predictable.

Native mode is ideal for:

  • Pure JavaScript projects (CJS or ESM)
  • Projects with no build step required
  • Applications where you want the snapshot to mirror your source layout exactly

If your project requires TypeScript compilation, monorepo resolution, or tree-shaking, see Bundle Mode instead.

Entry Detection

Hakobu discovers your application entry point from package.json:

  1. The "main" field (most common)
  2. The "module" field
  3. The "bin" field (for CLI tools)

You can also specify the entry explicitly:

hakobu ./my-project --entry src/index.js --output ./dist/app

Module System Support

ESM

  • "type": "module" in package.json -- full support
  • .mjs files -- full support
  • import.meta.url -- returns a file:///snapshot/... URL
  • Static import -- full support
  • Dynamic import() -- supported for static string paths
  • package.json "exports" map -- main entry and subpath exports
  • package.json "imports" map (#specifiers) -- supported

CJS

  • require() -- full support
  • require.resolve() -- full support
  • __dirname / __filename -- available, point to snapshot paths
  • module.exports / exports -- full support
  • .cjs files -- full support
  • JSON require('./data.json') -- full support

Mixed ESM/CJS

  • ESM entry with createRequire() for CJS dependencies -- works
  • CJS subpackage inside ESM root (via nested "type": "commonjs") -- works
  • .mjs in a CJS package / .cjs in an ESM package -- works

What Gets Included

Hakobu's analyzer traces your dependency graph starting from the entry point:

  • JavaScript files -- all files reachable via require() and static import
  • JSON files -- included as content
  • node_modules -- dependencies are traced and included
  • Assets -- files declared in the "assets" config (see Assets & Scripts)
  • Native addons -- .node files detected during analysis (see Native Addons)

Files that are not reachable from the entry point and not listed in assets are excluded from the binary.

Bytecode Compilation

Hakobu supports opt-in V8 bytecode compilation for CJS scripts. Bytecode pre-compiles your JavaScript into V8's internal format, which can improve startup time and provides light source obfuscation.

hakobu ./my-app --bytecode --output ./dist/app

Or via package.json:

package.json
{
  "hakobu": {
    "bytecode": true
  }
}
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 or extracted

To disable bytecode compilation when it is enabled by config, use:

hakobu ./my-app --no-bytecode --output ./dist/app

Bytecode is V8 version-specific. Executables must run on the same V8 version they were compiled with. Bytecode mode cannot be combined with --bundle (bundle produces ESM, which does not support bytecode).

Snapshot Creation

After analysis and optional bytecode compilation, Hakobu creates the final executable:

  1. Analyze -- trace the dependency graph from the entry point
  2. Collect -- gather all scripts, assets, and native addons
  3. Compile -- optionally compile CJS scripts to V8 bytecode
  4. Pack -- embed everything into the snapshot filesystem
  5. Produce -- inject the snapshot into the patched Node base binary

The result is a single self-contained executable with all your code and dependencies embedded.

On this page