Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 29 additions & 16 deletions docs-site/guide/compression.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
---
title: Compression
description: Shrink the embedded filesystem inside your pkg binary with Brotli or GZip.
description: Shrink the embedded filesystem inside your pkg binary with Brotli, GZip or Zstd.
---

# Compression

Pass `--compress Brotli` or `--compress GZip` to compress the contents of files stored in the executable. `-C` is a shortcut for `--compress`.
Pass `--compress Brotli`, `--compress GZip`, or `--compress Zstd` to compress the contents of files stored in the executable. `-C` is a shortcut for `--compress`.

::: code-group

```sh [Brotli (smaller)]
```sh [Zstd (best balance)]
pkg --compress Zstd index.js
```

```sh [Brotli (smallest)]
pkg --compress Brotli index.js
```

```sh [GZip (faster to decompress)]
```sh [GZip (widely compatible)]
pkg -C GZip index.js
```

```json [package.json]
{
"pkg": {
"compress": "Brotli"
"compress": "Zstd"
}
}
```
Expand All @@ -29,24 +33,33 @@ pkg -C GZip index.js

## How much does it save?

This option can reduce the size of the embedded filesystem by up to **60%**. The exact ratio depends on your project — heavy JavaScript (libraries with long variable names) compresses well, already-minified code less so.
This option can reduce the size of the embedded filesystem by **60-70%** on typical Node.js projects. The exact ratio depends on your project — heavy JavaScript (libraries with long variable names) compresses well, already-minified code less so.

The startup time of the application may actually be **slightly reduced** — smaller disk reads often outweigh the decompression cost.
The startup time of the application may actually be **slightly reduced** — smaller disk reads often outweigh the decompression cost, especially with Zstd.

## Brotli vs GZip
## Choosing an algorithm

| Algorithm | Compression ratio | Decompression speed | Use when |
| --------- | ----------------- | ------------------- | ------------------------------- |
| Brotli | Higher | Slower | Binary size matters most |
| GZip | Lower | Faster | Cold-start latency matters most |
| Algorithm | Compression ratio | Decompression speed | Use when |
| --------- | ----------------- | ------------------- | --------------------------------------------------- |
| Brotli | Highest | Slowest | Binary size is the only thing that matters |
| Zstd | High | Very fast | Balanced default — small binary and fast cold start |
| GZip | Lower | Fast | Older Node.js runtimes without Zstd support |

For most CLI tools, Brotli is the better default. For long-running services where the extra MB or two doesn't matter, GZip shaves a few ms off startup.
For most projects, **Zstd** is the best default — near-Brotli ratios with GZip-class decompression speed.

::: info Zstd availability
Zstd uses `node:zlib`'s `zstdCompress` / `zstdDecompress`, which were added in **Node.js 22.15.0**. The build host and the packaged Node runtime must both support it. Use Brotli if you need to target older Node 22.x releases.
:::

## SEA mode

::: warning Not supported in SEA mode
Compression is **not** available when packaging with `--sea`. The SEA binary layout uses a flat blob without per-file compression. If binary size is critical, stick with Standard mode. See [SEA vs Standard](/guide/sea-vs-standard).
:::
Compression also works with `--sea`. The SEA archive is compressed per-file at build time and decompressed lazily on first `fs.readFileSync` / `require()` at runtime, so only files you actually access pay the decompression cost.

```sh
pkg --sea --compress Zstd index.js
```

This closes most of the size gap between SEA-mode and Standard-mode binaries without a measurable cold-start regression for typical CLIs.

## Troubleshooting

Expand Down
2 changes: 1 addition & 1 deletion docs-site/guide/sea-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Not supported in enhanced SEA mode (incompatible with the VFS bootstrap). Set it

## Trade-offs vs Standard mode

Enhanced SEA builds faster and uses **official Node.js APIs**, but stores source in plaintext and skips compression. Workers, native addons, ESM, cross-compile and targets all work the same.
Enhanced SEA builds faster and uses **official Node.js APIs**. Per-file compression (`--compress Brotli` / `GZip` / `Zstd`) is supported and closes most of the size gap with Standard mode. Workers, native addons, ESM, cross-compile and targets all work the same.

For the full feature matrix and decision guide, see **[SEA vs Standard](/guide/sea-vs-standard)**.

Expand Down
29 changes: 14 additions & 15 deletions docs-site/guide/sea-vs-standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ description: The full comparison between Standard mode (patched Node.js, bytecod
**SEA mode** runs on **stock, unmodified Node.js**. No patches. No waiting for `pkg-fetch` to catch up. Security fixes and new Node versions are available the moment Node.js itself releases them.
:::

Everything else — compression, bytecode, worker threads, native addons — flows from that one decision.
Everything else — bytecode, worker threads, native addons, bundling strategy — flows from that one decision.

## Why stock binaries matter

Expand All @@ -25,26 +25,25 @@ Everything else — compression, bytecode, worker threads, native addons — flo

## Feature matrix

| Feature | **Standard** | **Enhanced SEA** |
| ------------------------------- | ---------------------------------------------------------------------- | ------------------------ |
| **Node.js binary** | Custom patched (`pkg-fetch`) | **Stock Node.js** ✨ |
| Source protection (V8 bytecode) | ✅ | ❌ plaintext |
| Compression (Brotli / GZip) | ✅ | |
| Build speed | Slower | **Faster** |
| Cross-compile | ⚠️ broken on Node 22 ([see](/guide/targets#cross-compilation-support)) | ✅ |
| Worker threads | ✅ | ✅ |
| Native addons | ✅ | ✅ |
| ESM + top-level await | Partial | ✅ every target |
| Maintenance burden | High — patch each Node release | **Low — stock binaries** |
| Security updates | Wait for `pkg-fetch` rebuild | **Immediate** |
| Future path | Tied to `pkg-fetch` | Migrates to `node:vfs` |
| Feature | **Standard** | **Enhanced SEA** |
| ---------------------------------- | ---------------------------------------------------------------------- | ------------------------ |
| **Node.js binary** | Custom patched (`pkg-fetch`) | **Stock Node.js** ✨ |
| Source protection (V8 bytecode) | ✅ | ❌ plaintext |
| Compression (Brotli / GZip / Zstd) | ✅ | |
| Build speed | Slower | **Faster** |
| Cross-compile | ⚠️ broken on Node 22 ([see](/guide/targets#cross-compilation-support)) | ✅ |
| Worker threads | ✅ | ✅ |
| Native addons | ✅ | ✅ |
| ESM + top-level await | Partial | ✅ every target |
| Maintenance burden | High — patch each Node release | **Low — stock binaries** |
| Security updates | Wait for `pkg-fetch` rebuild | **Immediate** |
| Future path | Tied to `pkg-fetch` | Migrates to `node:vfs` |

## When to pick which

Pick **Standard** when:

- You need **source protection** — your IP must not ship as plaintext JavaScript.
- You need **compression** — binary size matters more than build speed.

Pick **SEA** when:

Expand Down
Loading
Loading