HakobuHakobu

Programmatic API

Use Hakobu programmatically from Node.js scripts.

Hakobu exposes a programmatic API so you can drive packaging from build scripts, CI pipelines, or custom tooling without spawning a child process.

Installation

npm install @hakobu/hakobu

exec()

The primary export is the exec() function. It accepts an array of CLI argument strings -- the same arguments you would pass on the command line, minus the hakobu command itself.

import { exec } from '@hakobu/hakobu';

// Equivalent to: hakobu ./my-app --target node24-linux-x64 --output ./dist/app
await exec([
  './my-app',
  '--target', 'node24-linux-x64',
  '--output', './dist/app',
]);

Signature

export async function exec(argv: string[]): Promise<void>;

The function returns a Promise<void> that resolves when packaging completes successfully, or rejects on error.

Arguments

Pass CLI flags as individual array elements. The full set of recognized flags:

FlagTypeDescription
(positional)stringEntry file or directory (e.g. ., ./app.js)
-t, --targetstringComma-separated targets (e.g. node24-linux-x64,node24-win-x64)
-o, --outputstringOutput file path or directory
--out-path, --outdir, --out-dirstringOutput directory path
-c, --configstringPath to a config JSON file
-d, --debugbooleanEnable verbose packaging diagnostics
-b, --buildbooleanForce local build of base binary instead of downloading
-C, --compressstringCompression algorithm: None, Brotli, or GZip
--bytecodebooleanEnable V8 bytecode compilation (default: true)
--no-bytecodebooleanDisable bytecode, include source as plain JS
--publicbooleanMark top-level project sources as public
--public-packagesstringComma-separated list of packages to treat as public
--no-dictstringComma-separated packages to ignore dictionaries for
--optionsstringComma-separated V8 flags to bake into the executable
--signaturebooleanSign macOS executables (default: true)

Examples

Package for the current host platform:

await exec(['.']);

Package with compression:

await exec([
  './my-app',
  '--target', 'node24-linux-x64',
  '--output', './dist/app',
  '--compress', 'Brotli',
]);

Multi-target build:

await exec([
  '.',
  '--target', 'node24-linux-x64,node24-win-x64,node24-macos-arm64',
  '--output', './dist/',
]);

Build with debug output and V8 options:

await exec([
  './server.js',
  '--debug',
  '--options', 'max-heap-size=4096',
  '--output', './dist/server',
]);

packageMultiple()

For multi-target builds with structured input and output, the packageMultiple() function provides a higher-level interface.

import { packageMultiple } from '@hakobu/hakobu';

const results = await packageMultiple({
  projectRoot: '/path/to/project',
  targets: ['node24-linux-x64', 'node24-win-x64', 'node24-macos-arm64'],
  outputDir: './dist',
});

for (const r of results) {
  console.log(`${r.target.platform}-${r.target.arch}: ${r.outputPath} (${r.status})`);
}

PackageMultipleOptions

interface PackageMultipleOptions {
  projectRoot: string;
  targets: string[];
  outputDir?: string;     // Directory for output files (default: cwd)
  entry?: string;
  assets?: string[];
  externals?: string[];
  bundle?: boolean | string;
  bundleExternal?: string[];
}

PackageMultipleResult

interface PackageMultipleResult {
  target: { platform: string; arch: string; nodeRange: string };
  status: 'success' | 'failed';
  outputPath: string;     // Full path to the produced executable
  fileCount: number;
  error?: string;         // Error message if status === 'failed'
}

packageMultiple() internally runs analysis and bundling once, then produces each target binary in sequence. This is more efficient than calling exec() in a loop for each target.

TypeScript Types

Hakobu exports several TypeScript types you can use in your build scripts:

import type { NodeTarget, Target, SymLinks } from '@hakobu/hakobu';

NodeTarget

interface NodeTarget {
  nodeRange: string;          // e.g. "node24"
  arch: string;               // e.g. "x64", "arm64"
  platform: 'macos' | 'win' | 'linux';
  forceBuild?: boolean;
}

Target

Extends NodeTarget with resolved binary paths:

interface Target extends NodeTarget {
  binaryPath: string;
  output: string;
  fabricator: Target;
}

Error Handling

Both exec() and packageMultiple() throw on fatal errors. Wrap calls in try/catch for graceful handling:

import { exec } from '@hakobu/hakobu';

try {
  await exec(['.', '--target', 'node24-linux-x64', '--output', './dist/app']);
  console.log('Packaging succeeded');
} catch (error) {
  console.error('Packaging failed:', error.message);
  process.exit(1);
}

When using packageMultiple(), individual target failures do not throw. Instead, check the status field on each result. The function only throws for setup-level errors (e.g. invalid project root).

On this page