---
title: Packaging
url: "https://native-sdk.dev/docs/packaging"
docs_index: /llms.txt
lastUpdated: 2026-10-09
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

The Native SDK provides tooling to bundle your app into distributable packages for macOS, Linux, and Windows. A native-rendered app packages as a single binary plus icons, metadata, and whatever lives in your `assets/` directory — no browser runtime. On macOS the asset tree is mirrored into the bundle at its app-relative path (`Contents/Resources/assets/`), and the packaged app resolves relative asset paths (audio files, bundled fonts) against `Contents/Resources`, so a path like `assets/music/track.mp3` names the same file in a dev run and in the installed app. Keep large optional data out of `assets/` when you package, or it ships. The frontend-asset and CEF sections below apply only to apps that [embed web content](/docs/frontend); Chromium packaging is currently supported for macOS and includes the CEF runtime when `"web_engine": "chromium"` and the matching CEF layout is installed.

## Quick start

Build and package in two steps:

```bash
native build
native package --target macos
```

`native package` picks up `app.json` (falling back to `app.zon`) and the binary at `zig-out/bin/<name>` automatically; pass `--manifest`, `--binary`, or the other flags below for more control. Zero-config apps package without ejecting: the two commands above are the complete path from source to distributable, and `native eject` exists only for apps that want to own their build files. Apps that do own their build ([ejected](/docs/cli) or scaffolded with `--full`) also get a `zig build package` step that wires the same thing into the build graph.

## Build options

The build system exposes options that control platform, web engine, and build features:

<table>
  <thead>
    <tr>
      <th>
        Option
      </th>

      <th>
        Values
      </th>

      <th>
        Default
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `-Dplatform`
      </td>

      <td>
        `auto`

        ,

        `null`

        ,

        `macos`

        ,

        `linux`

        ,

        `windows`
      </td>

      <td>
        `auto`
      </td>

      <td>
        Target platform
      </td>
    </tr>

    <tr>
      <td>
        `-Dweb-engine`
      </td>

      <td>
        `system`

        ,

        `chromium`
      </td>

      <td>
        App manifest
      </td>

      <td>
        Temporary WebView engine override; Chromium is currently macOS-only
      </td>
    </tr>

    <tr>
      <td>
        `-Dcef-dir`
      </td>

      <td>
        path
      </td>

      <td>
        \--
      </td>

      <td>
        Temporary CEF distribution directory override
      </td>
    </tr>

    <tr>
      <td>
        `-Dtrace`
      </td>

      <td>
        `off`

        ,

        `events`

        ,

        `runtime`

        ,

        `all`
      </td>

      <td>
        `events`
      </td>

      <td>
        Trace output level
      </td>
    </tr>

    <tr>
      <td>
        `-Ddebug-overlay`
      </td>

      <td>
        `true`

        ,

        `false`
      </td>

      <td>
        `false`
      </td>

      <td>
        Enable debug overlay in WebView
      </td>
    </tr>

    <tr>
      <td>
        `-Dautomation`
      </td>

      <td>
        `true`

        ,

        `false`
      </td>

      <td>
        `false`
      </td>

      <td>
        Enable automation server
      </td>
    </tr>

    <tr>
      <td>
        `-Djs-bridge`
      </td>

      <td>
        `true`

        ,

        `false`
      </td>

      <td>
        `false`
      </td>

      <td>
        Enable JavaScript bridge
      </td>
    </tr>
  </tbody>
</table>

## App manifest packaging fields

The manifest drives packaging metadata:

```json title="app.json"
{
  "id": "com.example.myapp",
  "name": "myapp",
  "display_name": "My App",
  "version": "1.0.0",
  "icons": ["assets/icon.png"],
  "platforms": ["macos", "linux"],
  "web_engine": "system",
  "cef": { "dir": "third_party/cef/macos", "auto_install": false },
  "dmg": {
    "background": "assets/dmg-background.png",
    "window_width": 660,
    "window_height": 400,
    "app_position": { "x": 166, "y": 182 },
    "applications_position": { "x": 486, "y": 182 }
  }
}
```

<table>
  <thead>
    <tr>
      <th>
        Field
      </th>

      <th>
        Used for
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `id`
      </td>

      <td>
        macOS bundle identifier, Linux desktop file, log paths
      </td>
    </tr>

    <tr>
      <td>
        `display_name`
      </td>

      <td>
        Menu bar name, window title fallback
      </td>
    </tr>

    <tr>
      <td>
        `version`
      </td>

      <td>
        `Info.plist`

        version, package metadata
      </td>
    </tr>

    <tr>
      <td>
        `icons`
      </td>

      <td>
        One square source image; every platform's icon artifacts generate from it (see App icons)
      </td>
    </tr>

    <tr>
      <td>
        `file_associations`
      </td>

      <td>
        Document type metadata for macOS, Linux, and Windows registration artifacts
      </td>
    </tr>

    <tr>
      <td>
        `url_schemes`
      </td>

      <td>
        Custom protocol metadata for macOS, Linux, and Windows registration artifacts
      </td>
    </tr>

    <tr>
      <td>
        `platforms`
      </td>

      <td>
        Which platform packages to generate
      </td>
    </tr>

    <tr>
      <td>
        `dmg`
      </td>

      <td>
        Optional macOS disk-image branding and Finder layout; defaults already produce a styled drag-to-Applications image
      </td>
    </tr>
  </tbody>
</table>

## App icons

Drop one square image in your project — `assets/icon.png` (1:1, ideally 1024x1024) or `assets/icon.svg` — list it in `icons`, and packaging generates what each platform needs: a complete `.icns` for macOS (with the platform's rounded-rectangle icon shape and margins applied automatically, so full-bleed artwork looks native in the Dock), a multi-size `.ico` for Windows, and hicolor PNG size sets for Linux, plus asset-catalog and launcher-mipmap images for the mobile host skeletons. Artwork that already has transparent corners is treated as pre-shaped and ships unmasked. For art-directed control, a prebuilt `.icns` (macOS) or `.ico` (Windows) in `icons` always wins untouched. Everything is generated by the SDK's own rasterizer and encoders — no external tools. `native validate` checks the source up front (square, decodable, large enough) with the same messages packaging prints.

## macOS

### App bundle

`native package --target macos` creates a `.app` bundle with:

- `Contents/MacOS/<binary>` -- the compiled executable
- `Contents/Resources/AppIcon.icns` -- the app icon, generated from your icon source (or your prebuilt `.icns`, copied untouched under its own name)
- `Contents/Info.plist` -- generated from the app manifest
- `Contents/Resources/assets/` -- the app's asset tree, mirrored at its app-relative path so runtime asset paths resolve inside the bundle
- `Contents/Resources/dist/` -- frontend assets (if configured; replaces the `assets/` mirror)

macOS app bundles declare `LSMinimumSystemVersion` as `11.0`. File associations and URL schemes are emitted as `CFBundleDocumentTypes` and `CFBundleURLTypes` entries in `Contents/Info.plist`.

See [Code Signing](/docs/packaging/signing) for signing, notarization, and DMG creation.

Apps using [native updates](/docs/updates) add `--update-archive` to emit the ZIP consumed by the updater. The updater ZIP contains exactly the packaged `.app`; it is separate from the user-facing DMG.

### DMG archives

Add `--archive` to turn the packaged app into the disk image users download:

```bash
native build
native package --target macos --archive
```

Without any extra configuration, Native creates a 660×400 Finder window with a generated background and arrow, packages matching 1× and 2× representations for crisp Retina rendering, positions the app and an `/Applications` alias on either side, hides the Finder chrome, and compresses the result as a `.dmg`. The package diagnostic prints both the `.app` and `.dmg` paths.

Customize the presentation in `app.json`:

```json title="app.json"
"dmg": {
  "volume_name": "My App",
  "background": "assets/dmg-background.png",
  "window_width": 720,
  "window_height": 440,
  "icon_size": 144,
  "app_position": { "x": 180, "y": 210 },
  "applications_position": { "x": 540, "y": 210 },
  "applications_link": true
}
```

The window dimensions are the usable background canvas, excluding Finder's title bar. Positions are icon centers measured from the canvas's top-left corner. The background must be a project-relative PNG, JPEG, or TIFF at the configured window size; Finder displays it at its natural size. `native validate` and packaging reject malformed images or dimensions that do not match the configured canvas. For Retina artwork, put a double-sized sibling next to it using the `@2x` convention—for example, `dmg-background.png` at 720×440 and `dmg-background@2x.png` at 1440×880. Native discovers the pair, verifies that the sibling is exactly double-sized, and packages both representations. A prebuilt multi-resolution TIFF also works.

Omitting `background` keeps Native's generated Retina-aware gradient and draws the arrow between the configured app and Applications positions. Set `applications_link = false` only for a disk image that is not meant to use the conventional drag-to-install flow.

For complete control over which Finder items appear and where they sit, replace the fixed app/Applications pair with `items`:

```json title="app.json"
"dmg": {
  "background": "assets/dmg-background.png",
  "window_width": 760,
  "window_height": 480,
  "icon_size": 112,
  "items": [
    { "kind": "app", "position": { "x": 150, "y": 180 } },
    { "kind": "applications", "position": { "x": 610, "y": 180 } },
    { "kind": "file", "path": "README.pdf", "name": "Read Me.pdf", "position": { "x": 250, "y": 370 } },
    { "kind": "link", "path": "/Library/QuickLook", "name": "QuickLook", "position": { "x": 510, "y": 370 } }
  ]
}
```

An explicit list must contain exactly one `app`; its optional `name` changes only the bundle name shown in the DMG. `applications` creates the `/Applications` alias. `file` copies a project-relative file or directory, with an optional display `name`, while `link` creates a named symbolic link to an absolute path. When `items` is present, it replaces `app_position`, `applications_position`, and `applications_link`. The generated background draws its arrow whenever the list includes both `app` and `applications`.

## Linux

### Package structure

Linux packaging creates an install tree:

- `bin/<name>` -- the executable
- `share/applications/<name>.desktop` -- desktop entry file
- `share/icons/hicolor/.../<name>.png` -- icons at standard sizes
- `share/mime/packages/<name>.xml` -- shared MIME metadata when file associations are configured

```bash
native package --target linux --manifest app.json --binary zig-out/bin/MyApp
```

Configured file associations and URL schemes are added to the desktop file `MimeType` list. Extension-only associations get generated `application/x-...` MIME types with glob patterns in the shared MIME package.

## Windows

```bash
native package --target windows --manifest app.json --binary zig-out/bin/MyApp.exe
```

Windows packaging is in early development. The packager copies the binary and assets into a distributable directory structure and writes a multi-size `app-icon.ico` generated from your icon source (or copies a prebuilt `.ico` from `.icons` untouched). When file associations or URL schemes are configured, the artifact also includes `install/register-file-types.ps1`, which registers the package-local executable under the current user's `HKCU\Software\Classes` registry keys.

## Frontend assets

### Bundle assets

If your app has a frontend build step, bundle the output:

```bash
zig build bundle-assets
```

This copies the configured `dist` directory into the build output. Production packages serve these through `zero://app/`, so paths like `/assets/app.js` work without `file://` URLs.

### Configure in app.json

```json title="app.json"
"frontend": {
  "dist": "dist",
  "entry": "index.html",
  "spa_fallback": true
}
```

<table>
  <thead>
    <tr>
      <th>
        Field
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `dist`
      </td>

      <td>
        Path to the built frontend output
      </td>
    </tr>

    <tr>
      <td>
        `entry`
      </td>

      <td>
        HTML entry point within

        `dist`
      </td>
    </tr>

    <tr>
      <td>
        `spa_fallback`
      </td>

      <td>
        Serve

        `entry`

        for unknown routes (SPA mode)
      </td>
    </tr>
  </tbody>
</table>

## CEF bundling

When using the Chromium engine on macOS, bundle CEF alongside the app:

```bash
zig build cef-bundle -Dcef-dir=/path/to/cef
```

This copies the required CEF framework, libraries, and resources into the app bundle. The CEF distribution must match the macOS target architecture.

Use the same CEF version for install, build, package, and CI verification. The usual app-developer flow is:

```bash
native cef install --version <pinned-version>
zig build
native package --target macos
```

Set `"web_engine": "chromium"` and `"cef": { "dir": "third_party/cef/macos", "auto_install": false }` in `app.json` for the normal Chromium package path. Use `-Dweb-engine`, `--web-engine`, `-Dcef-dir`, or `--cef-dir` only when you need a one-off override.

Verify the Chromium macOS package layout locally with:

```bash
zig build test-package-cef-layout -Dplatform=macos
```

This gated check requires a local CEF layout or `-Dcef-auto-install=true` and verifies that the packaged app contains the CEF framework and resource files.

## Icon generation

Regenerate the SDK's default app icon from its vector source (`tools/generate_app_icon.zig`):

```bash
zig build generate-icon
```

This renders the full icon family (16 through 1024 px with @2x variants) through the SDK's own path rasterizer, assembles `assets/icon.icns` and `assets/icon.ico` with the built-in container writers (round-trip-validated, no external tools, any host OS), and also emits `assets/icon.png` (the 1024 px master) and an `assets/icon.svg` mirror for design handoff. The default follows the macOS icon grid — a centered 824x824 rounded-rect plate on the 1024 canvas with standard margins — so it sits correctly in the Dock next to system apps. `native init` scaffolds the same design as `assets/icon.png`, the one-image source the packaging pipeline generates every platform's icons from.

## Validation

Check that your manifest and environment are ready for packaging:

```bash
native doctor --manifest app.json --strict
native validate app.json
```

`doctor` checks the host environment, WebView availability, manifest validity, log paths, and optional CEF paths. Add `--strict` to fail on any warning. See [Debugging](/docs/debugging) for details on what `native doctor` checks.

## Platform shortcut commands

In addition to `native package --target <platform>`, the CLI provides shortcut commands:

```bash
native package-windows [--output path] [--binary path] [--service-binary path]
native package-linux [--output path] [--binary path] [--service-binary path]
native package-ios [--output path] [--binary path]
native package-android [--output path] [--binary path]
```

The desktop shortcuts use an explicit `--service-binary` when supplied; otherwise, service-bearing projects discover the normal `zig-out/bin/<app>_services[.exe]` build output just like `native package`.

## Platform targets

<table>
  <thead>
    <tr>
      <th>
        Target
      </th>

      <th>
        Status
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `macos`
      </td>

      <td>
        Full support:

        `.app`

        bundle, signing, notarization, DMG
      </td>
    </tr>

    <tr>
      <td>
        `linux`
      </td>

      <td>
        Desktop entry, icon install, binary packaging
      </td>
    </tr>

    <tr>
      <td>
        `windows`
      </td>

      <td>
        Early support: directory-based packaging
      </td>
    </tr>

    <tr>
      <td>
        `ios`
      </td>

      <td>
        Experimental: complete generated Xcode project around the toolkit UIKit host; ready for

        `xcodebuild archive`

        (code signing stays manual)
      </td>
    </tr>

    <tr>
      <td>
        `android`
      </td>

      <td>
        Experimental: complete generated host project around the toolkit Android host; the debug APK assembles from the generated project directly with the SDK build tools (store signing stays manual)
      </td>
    </tr>
  </tbody>
</table>

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)