---
title: 'Build'
description: napi build command in @napi-rs/cli, its cross-compilation flags, and the exact commands and environment it runs.
---

# Build

Build the NAPI-RS project

## Usage

```sh
# CLI
napi build [--options]
```

```typescript
// Programmatically
import { NapiCli } from '@napi-rs/cli'

new NapiCli().build({
  // options
})
```

## Options

| Options           | CLI Options           | type     | required | default | description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------- | --------------------- | -------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|                   | --help,-h             |          |          |         | get help                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| target            | --target,-t           | string   | false    |         | Build for the target triple, bypassed to <span class="chalk-green">cargo build --target</span>                                                                                                                                                                                                                                                                                                                                                                                              |
| cwd               | --cwd                 | string   | false    |         | The working directory of where napi command will be executed in, all other paths options are relative to this path                                                                                                                                                                                                                                                                                                                                                                          |
| manifestPath      | --manifest-path       | string   | false    |         | Path to <span class="chalk-rust">Cargo.toml</span>                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| configPath        | --config-path,-c      | string   | false    |         | Path to <span class="chalk-green">napi</span> config json file                                                                                                                                                                                                                                                                                                                                                                                                                              |
| packageJsonPath   | --package-json-path   | string   | false    |         | Path to <span class="chalk-green">package.json</span>                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| targetDir         | --target-dir          | string   | false    |         | Directory for all crate generated artifacts, see <span class="chalk-green">cargo build --target-dir</span>                                                                                                                                                                                                                                                                                                                                                                                  |
| outputDir         | --output-dir,-o       | string   | false    |         | Path to where all the built files would be put. Default to the crate folder                                                                                                                                                                                                                                                                                                                                                                                                                 |
| platform          | --platform            | boolean  | false    |         | Add platform triple to the generated nodejs binding file, eg: <span class="chalk-green">[name].linux-x64-gnu.node</span>                                                                                                                                                                                                                                                                                                                                                                    |
| jsPackageName     | --js-package-name     | string   | false    |         | Package name in generated js binding file. Only works with <span class="chalk-green">--platform</span> flag                                                                                                                                                                                                                                                                                                                                                                                 |
| constEnum         | --const-enum          | boolean  | false    |         | Whether generate const enum for typescript bindings                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| jsBinding         | --js                  | string   | false    |         | Path and filename of generated JS binding file. Only works with <span class="chalk-green">--platform</span> flag. Relative to <span class="chalk-green">--output-dir</span>.                                                                                                                                                                                                                                                                                                                |
| noJsBinding       | --no-js               | boolean  | false    |         | Whether to disable the generation JS binding file. Only works with <span class="chalk-green">--platform</span> flag.                                                                                                                                                                                                                                                                                                                                                                        |
| dts               | --dts                 | string   | false    |         | Path and filename of generated type def file. Relative to <span class="chalk-green">--output-dir</span>                                                                                                                                                                                                                                                                                                                                                                                     |
| dtsHeader         | --dts-header          | string   | false    |         | Custom file header for generated type def file. Only works when <span class="chalk-green">typedef</span> feature enabled.                                                                                                                                                                                                                                                                                                                                                                   |
| noDtsHeader       | --no-dts-header       | boolean  | false    |         | Whether to disable the default file header for generated type def file. Only works when <span class="chalk-green">typedef</span> feature enabled.                                                                                                                                                                                                                                                                                                                                           |
| dtsCache          | --dts-cache           | boolean  | false    | true    | Whether to enable the dts cache, default to true                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| esm               | --esm                 | boolean  | false    |         | Whether to emit an ESM JS binding file instead of CJS format. Only works with <span class="chalk-green">--platform</span> flag.                                                                                                                                                                                                                                                                                                                                                             |
| strip             | --strip,-s            | boolean  | false    |         | Whether strip the library to achieve the minimum file size                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| release           | --release,-r          | boolean  | false    |         | Build in release mode                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| verbose           | --verbose,-v          | boolean  | false    |         | Verbosely log build command trace                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| bin               | --bin                 | string   | false    |         | Build only the specified binary                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| package           | --package,-p          | string   | false    |         | Build the specified library or the one at cwd                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| profile           | --profile             | string   | false    |         | Build artifacts with the specified profile                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| crossCompile      | --cross-compile,-x    | boolean  | false    |         | [experimental] cross-compile by swapping the cargo subcommand: any Windows-platform target from a non-Windows host uses <span class="chalk-green">cargo-xwin</span> (which supports MSVC triples only; windows-gnu fails — see below); every other target uses <span class="chalk-green">cargo-zigbuild</span> (requires <span class="chalk-green">zig</span> on PATH). The selected subcommand is auto-installed on first use. Conflicts with <span class="chalk-green">--use-cross</span> |
| useCross          | --use-cross           | boolean  | false    |         | [experimental] <span class="chalk-warning">legacy, not recommended</span>: build inside a Docker/Podman container via <span class="chalk-green">cross</span> (cross-rs); prefer <span class="chalk-green">--use-napi-cross</span> or <span class="chalk-green">--cross-compile</span>. Requires <span class="chalk-green">cross</span> to be installed manually and a running container engine. Conflicts with <span class="chalk-green">--cross-compile</span>                             |
| useNapiCross      | --use-napi-cross      | boolean  | false    |         | [experimental] download a gcc cross toolchain from npm (<span class="chalk-green">@napi-rs/cross-toolchain</span>) and set linker/CC env vars. Linux glibc targets only: x64, arm64, armv7, ppc64le, s390x (glibc 2.17). Host must be Linux x64/arm64; on failure it warns and falls back to plain <span class="chalk-green">cargo</span>                                                                                                                                                   |
| watch             | --watch,-w            | boolean  | false    |         | watch the crate changes and build continuously with <span class="chalk-green">cargo-watch</span> crates                                                                                                                                                                                                                                                                                                                                                                                     |
| features          | --features,-F         | string[] | false    |         | Space-separated list of features to activate                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| allFeatures       | --all-features        | boolean  | false    |         | Activate all available features                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| noDefaultFeatures | --no-default-features | boolean  | false    |         | Do not activate the <span class="chalk-green">default</span> feature                                                                                                                                                                                                                                                                                                                                                                                                                        |

## Cross-compilation flags

`napi build` has three cross-compilation flags: `--use-napi-cross`, `--cross-compile` (`-x`) and `--use-cross`. All three are experimental: behavior may change between minor releases.

The recommended flags are `--use-napi-cross` for Linux glibc targets on a Linux x64/arm64 host, and `--cross-compile` (`-x`) for Windows MSVC targets from a non-Windows host and for musl targets. `-x` is also the fallback for glibc, macOS and FreeBSD targets when the preferred setup is not available on your host. Android, WASI and OpenHarmony targets need no cross flag at all: the CLI configures their toolchains from platform environment variables. `--use-cross` is legacy and not recommended, and the Docker-image based builds are deprecated. This page is a reference for what each flag does. To pick the right flag for your host and target, see [Cross build](../cross-build). For Alpine/musl specifics, see the [FAQ](../more/faq#build-for-linux-alpine).

Each flag changes exactly one thing about the build:

| Flag                     | What it changes                                     | Resulting command                                                          |
| ------------------------ | --------------------------------------------------- | -------------------------------------------------------------------------- |
| _(none)_                 | nothing                                             | `cargo build --target <triple>`                                            |
| `--use-cross`            | the **binary** only                                 | `cross build --target <triple>`                                            |
| `--cross-compile` / `-x` | the **subcommand** only (plus two env side effects) | `cargo zigbuild --target <triple>` or `cargo xwin build --target <triple>` |
| `--use-napi-cross`       | **env vars** only (linker, CC, sysroot)             | still `cargo build --target <triple>`                                      |

### Pick exactly one

::: warning
These flags do not combine. Pick exactly one. Two of the combinations print a
warning saying one flag will be ignored, but both mechanisms actually stay
active.

:::

| Combination                            | What actually happens                                                                                                                                                                |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--use-cross` + `--cross-compile`      | Hard error: the CLI refuses to build. (It may still auto-install cargo-xwin or cargo-zigbuild before erroring.)                                                                      |
| `--use-napi-cross` + `--use-cross`     | Prints a warning saying `--use-cross` will be ignored — but `cross` still runs, with host paths injected into its environment. Do not combine.                                       |
| `--use-napi-cross` + `--cross-compile` | Prints a warning saying `--cross-compile` will be ignored — but `cargo zigbuild` still runs, with the napi-cross env also set (the napi-cross linker wins over zig). Do not combine. |
| `--watch` + `--cross-compile`          | Produces an invalid command (`cargo watch ... -- cargo build zigbuild`). Do not combine.                                                                                             |

### Prerequisites

| Flag                                      | Installed for you                                                                                                                                                     | You must provide                                                                                                                                                                                                                                                                    |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-x`, non-Windows target (cargo-zigbuild) | <span class="chalk-green">cargo-zigbuild</span> via `cargo install` on first use (which can be slow).                                                                 | `zig` on `PATH`. The CLI never installs or checks zig; cargo-zigbuild errors if it is missing.                                                                                                                                                                                      |
| `-x`, Windows target (cargo-xwin)         | <span class="chalk-green">cargo-xwin</span> via `cargo install`, on first use. It downloads the Microsoft CRT and Windows SDK itself (the Microsoft license applies). | `clang` (e.g. `apt install clang` / `brew install llvm`) — zig is **not** used on this path. For dependencies that compile assembly, also the LLVM tools (`rustup component add llvm-tools`). The CLI checks none of these.                                                         |
| `--use-cross`                             | Nothing.                                                                                                                                                              | The `cross` binary (a missing binary fails with `spawn cross ENOENT`), plus a running Docker >= 20.10 or Podman >= 3.4.                                                                                                                                                             |
| `--use-napi-cross`                        | The gcc toolchain, downloaded automatically from npm (<span class="chalk-green">@napi-rs/cross-toolchain</span>) and cached under `~/.napi-rs/cross-toolchain`.       | `npm` on `PATH`, and a Linux x64 or arm64 host. The CLI does not check the host: on macOS or Windows the toolchain still downloads without error, and the Linux gcc then fails at link time. Any failure here only prints a warning and the build continues as plain `cargo build`. |

### Examples

One copy-paste command per flag:

```sh
# Linux glibc targets, from a Linux x64/arm64 host
napi build --release --target aarch64-unknown-linux-gnu --use-napi-cross

# Windows MSVC from a macOS/Linux host, musl, or the zigbuild fallback cases
napi build --release --target x86_64-unknown-linux-musl --cross-compile

# Legacy container build (not recommended)
napi build --release --target x86_64-unknown-linux-gnu --use-cross
```

## What `napi build` runs

`napi build` is a wrapper around one spawned command plus a set of environment variables. This section spells both out.

### The command

| Mode                                                               | Spawned command                                                          |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------ |
| No cross flag                                                      | `cargo build --target <triple>`                                          |
| `--use-napi-cross`                                                 | `cargo build --target <triple>` (only the env changes)                   |
| `--use-cross`                                                      | `cross build --target <triple>` (same args, same host-computed env)      |
| `--cross-compile`, target platform is Windows, host is not Windows | `cargo xwin build --target <triple>` (`XWIN_ARCH=x86` is set for `i686`) |
| `--cross-compile`, any other target                                | `cargo zigbuild --target <triple>`                                       |
| `--cross-compile`, target is Windows, host is Windows              | warns, then plain `cargo build --target <triple>`                        |

`--cross-compile` picks cargo-xwin by the target's **platform**: every `*-windows-*` triple built from a non-Windows host routes through cargo-xwin — including `x86_64-pc-windows-gnu`, not just MSVC. Being routed is not the same as being supported, though: cargo-xwin handles MSVC only, so for windows-gnu it configures nothing and the build fails at link time with ``error: linker `x86_64-w64-mingw32-gcc` not found``. Build that target without `-x`, with a mingw-w64 toolchain — see the windows-gnu note in [Recipes per target](../cross-build#recipes-per-target). Every non-Windows target goes through cargo-zigbuild — the CLI keeps no list of supported targets, and it uses zigbuild even when the target matches the host.

If the `CARGO` environment variable is set, the CLI spawns that binary instead — in every mode, including `--use-cross`, where it silently replaces `cross`.

### RUSTFLAGS

- Any `*musl*` target: the CLI appends `-C target-feature=-crt-static` to `RUSTFLAGS`.
- `--strip`: the CLI appends `-C link-arg=-s`.

Both are applied through the exported `RUSTFLAGS` environment variable. Cargo gives the env var precedence over `rustflags` in `.cargo/config.toml`, so once the CLI exports it, the rustflags from your `.cargo/config.toml` are ignored. If you need extra flags, add them to the `RUSTFLAGS` env var, not to `.cargo/config.toml`.

### C compiler

When both `TARGET_CC` and `CC` are set, `TARGET_CC` wins (since `@napi-rs/cli` 3.0.0-alpha.92).

### Default linkers for less common targets

Without `--cross-compile`, these targets get `CARGO_TARGET_<T>_LINKER` pointed at a cross gcc that **you must install yourself**. The CLI sets the env var without checking it: if the binary is missing, the build fails at link time. Your own `CARGO_TARGET_<T>_LINKER` env var always wins. With `--cross-compile` this table is skipped — linking is delegated to zig or xwin.

| Target                          | Linker set by the CLI          |
| ------------------------------- | ------------------------------ |
| `aarch64-unknown-linux-musl`    | `aarch64-linux-musl-gcc`       |
| `loongarch64-unknown-linux-gnu` | `loongarch64-linux-gnu-gcc-13` |
| `riscv64gc-unknown-linux-gnu`   | `riscv64-linux-gnu-gcc`        |
| `powerpc64le-unknown-linux-gnu` | `powerpc64le-linux-gnu-gcc`    |
| `s390x-unknown-linux-gnu`       | `s390x-linux-gnu-gcc`          |

### Android, WASI and OpenHarmony

These targets get their toolchain env from the CLI whenever the target platform matches — with or without any cross flag — but each platform has its own conditions:

- **Android**: linker/CC/AR env is built from `ANDROID_NDK_LATEST_HOME`. A missing variable only prints a warning — the env vars are still set, with broken paths, and the build fails at link time. The whole setup is skipped when the host itself is Android.
- **WASI**: `EMNAPI_LINK_DIR` is always set to the bundled emnapi (the CLI errors if the `emnapi`, `@emnapi/core` and `@emnapi/runtime` versions mismatch). The wasi-sdk linker/CC env is set only when `WASI_SDK_PATH` is set **and** the directory exists — otherwise linking falls back to cargo's default, rustup's bundled `rust-lld`.
- **OpenHarmony**: env is built from `$OHOS_SDK_PATH/native`, or from `OHOS_SDK_NATIVE` when `OHOS_SDK_PATH` is unset. If neither is set, the CLI warns and sets nothing.

## Passing flags to Cargo

Flags after `--` will be passed through to the cargo build command. For example:

```sh
napi build -- --locked
```

This will pass the `--locked` flag to `cargo build`, resulting in `cargo build --locked`.

## Note for `--js-package-name`

In the [Deep dive section](../introduction/getting-started#deep-dive), we recommended you publish your package under [`npm scope`](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/). But if you are migrating an existed package which is not under the [`npm scope`](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/) or you just don't want your package under an [`npm scope`](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/) , you may trigger the [_npm spam detection_](https://stackoverflow.com/questions/48668389/npm-publish-failed-with-package-name-triggered-spam-detection/54135900#54135900) while publishing the native platform packages. Like `snappy-darwin-x64` `snappy-darwin-arm64` etc...

In this case, you can publish your platform packages under [`npm scope`](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/) to avoid the [_npm spam detection_](https://stackoverflow.com/questions/48668389/npm-publish-failed-with-package-name-triggered-spam-detection/54135900#54135900). And your users don't need to care about the platform native packages in `optionalDependencies`. Like [`snappy`](https://github.com/Brooooooklyn/snappy/), users only need to install it via `yarn add snappy`. But platform native packages are under `@napi-rs` scope:

```json
{
  "name": "snappy",
  "version": "7.0.0",
  "optionalDependencies": {
    "@napi-rs/snappy-win32-x64-msvc": "7.0.0",
    "@napi-rs/snappy-darwin-x64": "7.0.0",
    "@napi-rs/snappy-linux-x64-gnu": "7.0.0",
    "@napi-rs/snappy-linux-x64-musl": "7.0.0",
    "@napi-rs/snappy-linux-arm64-gnu": "7.0.0",
    "@napi-rs/snappy-win32-ia32-msvc": "7.0.0",
    "@napi-rs/snappy-linux-arm-gnueabihf": "7.0.0",
    "@napi-rs/snappy-darwin-arm64": "7.0.0",
    "@napi-rs/snappy-android-arm64": "7.0.0",
    "@napi-rs/snappy-android-arm-eabi": "7.0.0",
    "@napi-rs/snappy-freebsd-x64": "7.0.0",
    "@napi-rs/snappy-linux-arm64-musl": "7.0.0",
    "@napi-rs/snappy-win32-arm64-msvc": "7.0.0"
  }
}
```

For this case, `@napi-rs/cli` provides the `--js-package-name` to override generated package loading logic. For example in `snappy` we have <span class="chalk-green">package.json</span> like this:

```json
{
  "name": "snappy",
  "version": "7.0.0",
  "napi": {
    "name": "snappy"
  }
}
```

Without the `--js-package-name` flag, `@napi-rs/cli` will generate JavaScript binding to load platform native packages for you:

**index.js**

```js {10,22}
switch (platform) {
  case 'darwin':
    switch (arch) {
      case 'x64':
        localFileExisted = existsSync(join(__dirname, 'snappy.darwin-x64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./snappy.darwin-x64.node')
          } else {
            nativeBinding = require('snappy-darwin-x64')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'arm64':
        localFileExisted = existsSync(join(__dirname, 'snappy.darwin-arm64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./snappy.darwin-arm64.node')
          } else {
            nativeBinding = require('snappy-darwin-arm64')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on macOS: ${arch}`)
    }
    break
    ...
}
```

This isn't what we want. So build it with `--js-package-name` to override the `package name` in generated JavaScript binding file: `napi build --release --platform --js-package-name @napi-rs/snappy`. Then the generated JavaScript file will become:

**index.js**

```js {10,22}
switch (platform) {
  case 'darwin':
    switch (arch) {
      case 'x64':
        localFileExisted = existsSync(join(__dirname, 'snappy.darwin-x64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./snappy.darwin-x64.node')
          } else {
            nativeBinding = require('@napi-rs/snappy-darwin-x64')
          }
        } catch (e) {
          loadError = e
        }
        break
      case 'arm64':
        localFileExisted = existsSync(join(__dirname, 'snappy.darwin-arm64.node'))
        try {
          if (localFileExisted) {
            nativeBinding = require('./snappy.darwin-arm64.node')
          } else {
            nativeBinding = require('@napi-rs/snappy-darwin-arm64')
          }
        } catch (e) {
          loadError = e
        }
        break
      default:
        throw new Error(`Unsupported architecture on macOS: ${arch}`)
    }
    break
    ...
}
```
