[Bug] v13: npm install on Windows still invokes Python/node-gyp even when bundled prebuilt exists
Description
Version: 13.0.0 / 13.0.1
Platform: Windows (win32-x64)
Severity: Breaks install for all Windows users without a full C++ / Python toolchain
What happens
Installing better-sqlite3@13 on Windows without Python and Visual C++ Build Tools fails:
gyp ERR! find Python
gyp ERR! find Python Python is not set from command line or npm configuration
gyp ERR! find Python Python is not set from the environment variable PYTHON
gyp ERR! find Python ...
gyp ERR! not ok
This occurs even though prebuilds/win32-x64.node is included in the published package and is ready to use — no compilation is necessary.
Root cause
package.json in v13 has no install script. When npm/pnpm encounters a binding.gyp without an install script, it automatically invokes node-gyp rebuild as the implicit install script.
node-gyp rebuild requires Python in order to run the GYP configure step — and the configure step must run before GYP can evaluate any variables, including the prebuild_exists detection in binding.gyp:
# npm's implicit node-gyp rebuild should do nothing when the package
# contains a prebuild for the host. Explicit build scripts override this.
'force_build%': 0,
'prebuild_exists%': '<!@(node lib/binding.js)',
The intent here is clearly correct — if prebuild_exists is 1, the build is skipped. But Python is consumed before this check can happen. The prebuilt detection therefore never prevents Python from being required.
The v12 behavior (correct)
v12 used prebuild-install as the install script. prebuild-install runs entirely in Node.js and checks for the bundled binary before node-gyp is ever touched. If the prebuilt is found, it exits 0 immediately — Python is never needed.
Suggested fix
Add a minimal install script (node install.js or similar) that:
- Calls
getPrebuildPath() from lib/binding.js (already exported).
- If a prebuilt is found, exits
0 immediately.
- Only if no prebuilt is found, falls through to
node-gyp rebuild.
The logic already exists in lib/binding.js — it just needs to be the entry point rather than buried inside the GYP build system:
// install.js
'use strict';
const { getPrebuildPath } = require('./lib/binding');
if (getPrebuildPath()) {
// Prebuilt binary found — nothing to do.
process.exit(0);
}
// No prebuilt for this platform/arch — compile from source.
const { execFileSync } = require('child_process');
execFileSync(process.execPath, [
require.resolve('node-gyp/bin/node-gyp.js'),
'rebuild',
], { stdio: 'inherit' });
And in package.json:
"scripts": {
"install": "node install.js"
}
Workaround (for affected users)
If you cannot install v13, stay on v12:
npm install better-sqlite3@^12
v12 ships Node.js 24/26 prebuilts and behaves correctly on Windows without a build toolchain.
This effectively reverts the Windows install experience to broken for the majority of users who don't have Python and MSVC installed, despite the package bundling a ready-to-use binary. It would be great to get this resolved in a v13.0.2 patch.
Full disclosure: this issue was written with the help of an LLM, after troubleshooting the issue together.
[Bug] v13:
npm installon Windows still invokes Python/node-gyp even when bundled prebuilt existsDescription
Version: 13.0.0 / 13.0.1
Platform: Windows (win32-x64)
Severity: Breaks install for all Windows users without a full C++ / Python toolchain
What happens
Installing
better-sqlite3@13on Windows without Python and Visual C++ Build Tools fails:This occurs even though
prebuilds/win32-x64.nodeis included in the published package and is ready to use — no compilation is necessary.Root cause
package.jsonin v13 has noinstallscript. When npm/pnpm encounters abinding.gypwithout an install script, it automatically invokesnode-gyp rebuildas the implicit install script.node-gyp rebuildrequires Python in order to run the GYP configure step — and the configure step must run before GYP can evaluate any variables, including theprebuild_existsdetection inbinding.gyp:The intent here is clearly correct — if
prebuild_existsis1, the build is skipped. But Python is consumed before this check can happen. The prebuilt detection therefore never prevents Python from being required.The v12 behavior (correct)
v12 used
prebuild-installas theinstallscript.prebuild-installruns entirely in Node.js and checks for the bundled binary before node-gyp is ever touched. If the prebuilt is found, it exits 0 immediately — Python is never needed.Suggested fix
Add a minimal
installscript (node install.jsor similar) that:getPrebuildPath()fromlib/binding.js(already exported).0immediately.node-gyp rebuild.The logic already exists in
lib/binding.js— it just needs to be the entry point rather than buried inside the GYP build system:And in
package.json:Workaround (for affected users)
If you cannot install v13, stay on v12:
v12 ships Node.js 24/26 prebuilts and behaves correctly on Windows without a build toolchain.
This effectively reverts the Windows install experience to broken for the majority of users who don't have Python and MSVC installed, despite the package bundling a ready-to-use binary. It would be great to get this resolved in a v13.0.2 patch.
Full disclosure: this issue was written with the help of an LLM, after troubleshooting the issue together.