Node-GYP Build (Prebuild-aware Native Addon Loader)
node-gyp-build is a critical utility for distributing Node.js native addons, acting as a wrapper around node-gyp to support prebuilt binaries. Its primary function is to check for and load prebuilt native modules, or fall back to compiling from source using node-gyp if no suitable prebuild is found. This significantly reduces installation times and improves cross-platform compatibility by avoiding local compilation for many users. It works in tandem with 'prebuildify' to generate and bundle these prebuilds, handling various target environments including Node.js and Electron, and accommodating different libc (e.g., glibc, musl) and ARM architectures. The current stable version is 4.8.4, with releases generally following the node-gyp and prebuildify ecosystem, focusing on stability and compatibility with new Node.js ABIs and platforms. Key differentiators include its robust prebuild discovery mechanism, seamless integration into npm install scripts, and support for complex prebuild tagging.
Common errors
-
Error: No native build was found for platform <platform> architecture <arch> abi <abi> and libstdc++ <glibc|musl> (where applicable)
cause The required prebuilt binary for the current operating system, architecture, Node.js ABI, or libc environment is either missing from the bundled prebuilds or uses an outdated naming convention not recognized by node-gyp-build v4+.fixEnsure your project's `prebuild` script (using `prebuildify v3+`) successfully generates prebuilds for all target environments. If you are a user, try `npm install --build-from-source` to force local compilation, or ensure the library maintainers provide the necessary prebuilds. -
Error: Cannot find module 'bindings'
cause The native module's JavaScript wrapper is still attempting to use the `bindings` package to load the native addon, rather than `node-gyp-build`.fixLocate the `require('bindings')` call in your module's entry point (e.g., `index.js`) and replace it with `require('node-gyp-build')(__dirname)`. -
npm ERR! Failed at the <package-name>@<version> install script. node-gyp-build
cause The `node-gyp-build` command, executed via the `install` script in `package.json`, encountered an error. This usually indicates a problem with native compilation (if falling back to source) or an inability to find prebuilds.fixExamine the npm output preceding this error for more specific details from `node-gyp-build` or `node-gyp`. Common issues include missing build tools (e.g., Python, C++ compiler), incorrect `binding.gyp` configuration, or lack of matching prebuilds.
Warnings
- breaking The naming conventions for prebuilt binaries underwent significant changes starting with node-gyp-build v4 and prebuildify v3. Prebuilds generated with older versions of prebuildify will not be recognized or loaded correctly by node-gyp-build v4+.
- gotcha When `node-gyp-build` is configured as the `install` script, users can explicitly force a compilation from source by running `npm install --build-from-source`. This bypasses prebuilds and attempts a local compilation.
- gotcha Detection of specific prebuild flavors (e.g., `musl` for Alpine Linux, or specific ARM architecture versions like `armv7`) relies on `node-gyp-build`'s auto-detection or explicit environment variables (`LIBC`, `ARM_VERSION`). Incorrect settings or detection can lead to loading a less optimal prebuild or an unnecessary source compilation.
- gotcha Native addons built with N-API typically offer better forward compatibility across Node.js versions. Older NAN-based (Native Abstractions for Node.js) addons are more susceptible to ABI breakage with new Node.js major versions, potentially requiring frequent prebuild updates.
Install
-
npm install node-gyp-build -
yarn add node-gyp-build -
pnpm add node-gyp-build
Imports
- <default function>
import loadBinding from 'node-gyp-build'; const binding = loadBinding(__dirname);
const loadBinding = require('node-gyp-build'); const binding = loadBinding(__dirname); - <default function invocation>
import { build } from 'node-gyp-build';const binding = require('node-gyp-build')(__dirname);
Quickstart
// package.json - configure the 'install' script and dependencies
{
"name": "my-native-hello-world",
"version": "1.0.0",
"description": "A sample native module using node-gyp-build and prebuildify",
"main": "index.js",
"scripts": {
"install": "node-gyp-build",
"prebuild": "prebuildify --strip", // Requires 'prebuildify' to be installed locally
"postinstall": "node index.js" // To test if the binding loads after install
},
"dependencies": {
"node-gyp-build": "^4.0.0"
}
}
// index.js - load the native binding
const path = require('path');
console.log("Attempting to load native binding...");
let helloBinding;
try {
helloBinding = require('node-gyp-build')(__dirname);
console.log("Native binding loaded successfully!");
// Assuming the native addon exports a 'hello' function
if (typeof helloBinding.hello === 'function') {
const message = helloBinding.hello();
console.log(`Native greeting: ${message}`); // Expected: 'Hello from native!'
} else {
console.warn("Native binding does not export a 'hello' function.");
}
} catch (e) {
console.error(`Failed to load native binding: ${e.message}`);
console.warn("Consider running 'npm install --build-from-source' if prebuilds are missing or incompatible.");
// You might want to provide a fallback or re-throw based on your application's needs
}
/*
// Example of a minimal C++ source file for 'hello.cc' (requires a binding.gyp)
// Save this as hello.cc in your project root.
#include <napi.h>
Napi::String Method(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
return Napi::String::New(env, "Hello from native!");
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "hello"), Napi::Function::New(env, Method));
return exports;
}
NODE_API_MODULE(hello, Init)
// Example binding.gyp for 'hello.cc'
// Save this as binding.gyp in your project root.
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ]
}
]
}
*/