Docs
CLI
Build

Build

Build the NAPI-RS project

Usage

# CLI
napi build [--options]
// Programmatically
import { NapiCli } from '@napi-rs/cli'
 
new NapiCli().build({
  // options
})

Options

OptionsCLI Optionstyperequireddefaultdescription
--help,-hget help
target--target,-tstringfalseBuild for the target triple, bypassed to cargo build --target
cwd--cwdstringfalseThe working directory of where napi command will be executed in, all other paths options are relative to this path
manifestPath--manifest-pathstringfalsePath to Cargo.toml
configPath--config-path,-cstringfalsePath to napi config json file
packageJsonPath--package-json-pathstringfalsePath to package.json
targetDir--target-dirstringfalseDirectory for all crate generated artifacts, see cargo build --target-dir
outputDir--output-dir,-ostringfalsePath to where all the built files would be put. Default to the crate folder
platform--platformbooleanfalseAdd platform triple to the generated nodejs binding file, eg: [name].linux-x64-gnu.node
jsPackageName--js-package-namestringfalsePackage name in generated js binding file. Only works with --platform flag
constEnum--const-enumbooleanfalseWhether generate const enum for typescript bindings
jsBinding--jsstringfalsePath and filename of generated JS binding file. Only works with --platform flag. Relative to --output-dir.
noJsBinding--no-jsbooleanfalseWhether to disable the generation JS binding file. Only works with --platform flag.
dts--dtsstringfalsePath and filename of generated type def file. Relative to --output-dir
dtsHeader--dts-headerstringfalseCustom file header for generated type def file. Only works when typedef feature enabled.
noDtsHeader--no-dts-headerbooleanfalseWhether to disable the default file header for generated type def file. Only works when typedef feature enabled.
dtsCache--dts-cachebooleanfalsetrueWhether to enable the dts cache, default to true
esm--esmbooleanfalseWhether to emit an ESM JS binding file instead of CJS format. Only works with --platform flag.
strip--strip,-sbooleanfalseWhether strip the library to achieve the minimum file size
release--release,-rbooleanfalseBuild in release mode
verbose--verbose,-vbooleanfalseVerbosely log build command trace
bin--binstringfalseBuild only the specified binary
package--package,-pstringfalseBuild the specified library or the one at cwd
profile--profilestringfalseBuild artifacts with the specified profile
crossCompile--cross-compile,-xbooleanfalse[experimental] cross-compile for the specified target with cargo-xwin on windows and cargo-zigbuild on other platform
useCross--use-crossbooleanfalse[experimental] use cross instead of cargo
useNapiCross--use-napi-crossbooleanfalse[experimental] use @napi-rs/cross-toolchain to cross-compile Linux arm/arm64/x64 gnu targets.
watch--watch,-wbooleanfalsewatch the crate changes and build continuously with cargo-watch crates
features--features,-Fstring[]falseSpace-separated list of features to activate
allFeatures--all-featuresbooleanfalseActivate all available features
noDefaultFeatures--no-default-featuresbooleanfalseDo not activate the default feature

Note for --js-package-name

In the Deep dive section, we recommended you publish your package under npm scope (opens in a new tab). But if you are migrating an existed package which is not under the npm scope (opens in a new tab) or you just don't want your package under an npm scope (opens in a new tab) , you may trigger the npm spam detection (opens in a new tab) 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 (opens in a new tab) to avoid the npm spam detection (opens in a new tab). And your users don't need to care about the platform native packages in optionalDependencies. Like snappy (opens in a new tab), users only need to install it via yarn add snappy. But platform native packages are under @napi-rs scope:

{
  "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 package.json like this:

{
  "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
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
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
    ...
}