node-gyp Build Failing? Native Module Fixes for bcrypt, sharp, esbuild
node-gyp rebuild failed, .node binary missing, native module won't compile — whatever the cause, here's the fix.
Covers native modules that install scripts (bcrypt, sharp, esbuild, puppeteer, node-sass), C++17 toolchain requirements per platform, and the npm approve-scripts workflow introduced in npm v12.
Why Native Modules Break
For 12 years, npm has automatically detected binding.gyp files and run node-gyp rebuild post-install. This worked — but it meant any package with a binding.gyp could execute arbitrary code during install. npm v12 closes this: zero postinstall scripts execute unless explicitly approved, per package. But even on older npm versions, native compilation can fail due to missing build tools, wrong Python version, or outdated compilers. This guide covers all causes.
The Chain That Breaks
1. npm install downloads package
2. Package has "scripts": {"install": "node-gyp rebuild"} or binding.gyp
3. npm 11: runs it automatically
4. npm 12: skips it silently
5. Your app tries require('bcrypt') → Cannot find module './lib/binding/napi-v3/bcrypt_lib.node'
The fix is simple in concept: approve trusted packages. The complexity is that every platform, every package, and every CI environment has its own gotchas.
node-gyp & C++17: Toolchain Requirements
node-gyp 12.x (bundled with npm v12) requires a C++17 compiler. This is a hard requirement — native addons with C++11 or C++14 code paths will fail to compile. Even on older npm/node-gyp versions, an outdated compiler is the #1 cause of native build failures.
Platform Toolchain Requirements
Linux
Minimum: gcc 8+ or clang 7+
Ubuntu/Debian: apt-get install build-essential python3 (Ubuntu 22.04+ ships gcc 11)
Alpine: apk add build-base python3
CentOS/RHEL 7: Default gcc 4.8 — must install devtoolset-8: yum install centos-release-scl && yum install devtoolset-8
Verify: gcc --version | head -1 should show ≥ 8.0
Windows
Minimum: Visual Studio 2022 with "Desktop development with C++" workload
Alternative: npm install -g windows-build-tools (installs VS Build Tools + Python)
npm config: npm config set msvs_version 2022
Common error: MSBuild.exe not found — VS 2022 Build Tools not installed or PATH not set
Verify: npm config get msvs_version should return "2022"
macOS
Minimum: Xcode 14+ Command Line Tools
Install: xcode-select --install
Apple Silicon (arm64): Native compilation works; cross-compilation from x64 to arm64 requires --target_arch=arm64
CI note: GitHub Actions macOS runners need sudo xcode-select -s /Applications/Xcode.app to accept license
Per-Package Fix Guide
bcrypt
What breaks: C++ addon compilation via node-gyp rebuild
Fix: npm approve-scripts bcrypt — one-time approval, persists in package.json
CI fix: Add npm approve-scripts bcrypt before npm test in your CI workflow
C++17 note: bcrypt 5.x+ uses N-API, compiles with any C++17 compiler. If you're on bcrypt 3.x, upgrade.
Alternative: bcryptjs (pure JS, no native deps) — 30% slower but zero compilation headaches
sharp
What breaks: libvips native binding compilation
Fix: npm approve-scripts sharp
Prebuilt binaries: sharp ships prebuilt binaries for most platforms. If you're on x64 Linux/macOS/Windows, you may not need compilation at all — but the script still needs approval for the install check
libvips dependency: On Linux, prebuilt binaries bundle libvips. On Alpine, install apk add vips-dev for source fallback
Verify: node -e "console.log(require('sharp').versions)"
esbuild
What breaks: Native Go binary installation script
Fix: npm approve-scripts esbuild
Good news: esbuild ships platform-specific binaries — the "script" just picks the right one. No C++ compiler needed.
Postinstall: If you see warnings about esbuild's postinstall, it's downloading the binary, not compiling. Safe to approve.
node-sass (deprecated — migrate)
What breaks: C++ binding to LibSass
Short-term: npm approve-scripts node-sass
Recommended: Migrate to sass (dart-sass). node-sass is deprecated, and its C++ compilation chain is fragile on npm v12 + C++17. Migration: npm uninstall node-sass && npm install sass. The API is mostly compatible — sass.renderSync() → sass.compileString().
Puppeteer
What breaks: Chromium download postinstall script
Fix: npm approve-scripts puppeteer
CI note: Puppeteer's download can add 300MB to CI runs. Install puppeteer-core instead if you provide Chromium separately (e.g., via @sparticuz/chromium on Lambda).
Common Native Module Errors
P0 "Cannot find module X.node" after npm install
npm v12 skipped the native build script. Fix: npm approve-scripts <pkg> then reinstall. Pro tip: Run npm ls --depth=0 2>&1 | grep -E '(sharp|bcrypt|esbuild|node-sass)' to find all native deps in your project, then approve each one.
P0 node-gyp rebuild failed: C++17 required
Your compiler is too old. Error message: error: no template named 'string_view' in namespace 'std' or error: 'if constexpr' requires C++17. Fix: upgrade gcc to 8+, install VS 2022 on Windows, or Xcode 14+ on macOS.
P1 NODE_MODULE_VERSION mismatch
The .node binary was compiled for a different Node.js version. Error: was compiled against a different Node.js version using NODE_MODULE_VERSION XX. Fix: npm rebuild <pkg> to recompile against your current Node.js version. If using Docker, make sure the Node.js version in the build stage matches the runtime stage.
P1 MSBuild.exe not found on Windows
Visual Studio Build Tools are missing or npm can't find them. Fix: npm install -g windows-build-tools or install "Desktop development with C++" from Visual Studio 2022. Then npm config set msvs_version 2022.
P1 GLIBCXX version mismatch on Linux
Prebuilt binary was compiled with a newer libstdc++ than your system has. Error: /lib64/libstdc++.so.6: version GLIBCXX_3.4.26 not found. Fix: either compile from source (npm rebuild <pkg> --build-from-source) or update your system's libstdc++ (apt-get install libstdc++6 on Ubuntu 22.04+).
Bulk Approval Script
For monorepos or projects with many native deps, approve them all at once:
# Find all packages with install/preinstall/postinstall scripts or binding.gyp
npx detect-native-modules 2>/dev/null || npm ls --depth=0 --json 2>/dev/null | \
node -e "
const data=JSON.parse(require('fs').readFileSync(0,'utf8'));
function findNative(deps){
if(!deps) return [];
return Object.entries(deps).filter(([k,v])=>
(v.peerMissing!==true && (v._resolved && v._resolved.includes('git+')))
).map(([k])=>k);
}
// Approve common native packages
['sharp','bcrypt','esbuild','puppeteer','node-sass','node-gyp'].forEach(p=>{
try{require(p); console.log('✓',p,'already present')}
catch(e){console.log('−',p,'not installed')}
});
"
FAQ
Why does bcrypt fail to install on npm v12?
bcrypt's install script (which runs node-gyp rebuild) is blocked by npm v12's new script policy. Fix: npm approve-scripts bcrypt then npm install. After approval, bcrypt works identically. If you're still on bcrypt 3.x, upgrade to 5.x for N-API support and better C++17 compatibility.
How do I approve native modules in a monorepo?
The npm approve-scripts must be run from each workspace directory — the root allowlist does not propagate. Script: for ws in $(npm ls --workspaces --json 2>/dev/null | node -e "process.stdin.on('data',d=>JSON.parse(d).forEach(w=>console.log(w)))"); do cd $ws && npm approve-scripts <pkg>; done. Or install npm approve-scripts at the root with --workspaces if your npm version supports it.
node-gyp rebuild succeeds locally but fails in Docker
Your Docker image is missing build tools. node:XX-slim images intentionally omit gcc/g++/python. Add to Dockerfile: apt-get install -y build-essential python3. For Alpine: apk add build-base python3. Also check that the Node.js version in your Dockerfile matches what the native module was prebuilt for.
Do I need C++17 for all native modules or just some?
node-gyp 12.x requires C++17 for compilation itself, regardless of what the native addon uses. Even if a package only uses C++11 features, the node-gyp build system needs a C++17-capable compiler. The good news: most packages (sharp, esbuild, puppeteer) ship prebuilt binaries and don't compile anything — they just need the install script approved so the binary download runs.
sharp installs but won't run after npm v12 upgrade
Sharp's prebuilt binary was downloaded but the install script (which validates it) was skipped. Run npm approve-scripts sharp && npm rebuild sharp. If that fails, sharp is trying to compile from source — check that libvips is installed (apt-get install libvips-dev on Debian/Ubuntu) and your C++17 compiler is available.
How to find all native modules in my project before upgrading?
Run npm ls --depth=99 --json 2>/dev/null | node -e "const d=JSON.parse(require('fs').readFileSync(0,'utf8'));function walk(deps){const n=[];if(!deps)return n;for(const[k,v]of Object.entries(deps)){try{const p=require(k+'/package.json');if(p.scripts&&(p.scripts.install||p.scripts.preinstall||p.scripts.postinstall))n.push(k+': '+Object.keys(p.scripts).filter(s=>['install','preinstall','postinstall'].includes(s)).join(', '))}catch(e){}};return n}console.log(walk(d.dependencies).join('\n')||'No native modules found')". Also check for binding.gyp files: find node_modules -name 'binding.gyp' -maxdepth 3 2>/dev/null.
Related Guides:
CI/CD Pipeline ← Migration Guide