You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 1, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Jul 1, 2026. It is now read-only.
node-sqlite3+bun single-exec does not correctly import the NAPI node_sqlite3.node #1843
Bun has a feature to compile a standalone executable, but if node-sqlite3 is a dependency, it doesn't work due to an incorrect import of the node-sqlite3 binding using the bindings library.
I can fix this with a PR if allowed. It simply requires a direct require to node_sqlite3.node without needing the library, as it seems the path build/Release/node_sqlite3.node is always predictable.
It would look something like this in lib/sqlite3-binding.js:
Of course, this only works if the path ../build/Release/node_sqlite3.node is predictable, so I would need more info on how this file is compiled.
However, with this patch, Bun can require the NAPI directly, and with this, the Bun compiler works well, creating the standalone executable generated by bun build without any issues.
Steps to Reproduce
Create a blank project with bun init and bun add sqlite3 (the error occurs regardless of whether you install it with bun or node/npm).
Create an index.js file with any code; in this case, I will use the code from the "Usage" section of node-sqlite3/README.md as an example.
constsqlite3=require('sqlite3').verbose();constdb=newsqlite3.Database(':memory:');db.serialize(()=>{db.run("CREATE TABLE lorem (info TEXT)");conststmt=db.prepare("INSERT INTO lorem VALUES (?)");for(leti=0;i<10;i++){stmt.run("Ipsum "+i);}stmt.finalize();db.each("SELECT rowid AS id, info FROM lorem",(err,row)=>{console.log(row.id+": "+row.info);});});db.close();
Run bun build --compile --outfile myExecutable index.js
(note: on my system, I add this flag to the command: --target=bun-linux-64)
Now run ./myExecutable and you will receive an error similar to this:
149 | dir = process.cwd();
150 | }
151 | if (exists(join(dir, "package.json")) || exists(join(dir, "node_modules"))) {
152 | return dir;
153 | }
154 | throw new Error('Could not find module root given file: "' + file + '". Do you have a `package.json` file? ');
^
error: Could not find module root given file: "/$bunfs/root/main". Do you have a `package.json` file?
at getRoot (/$bunfs/root/main:154:15)
at bindings (/$bunfs/root/main:84:41)
at <anonymous> (/$bunfs/root/main:164:38)
at <anonymous> (/$bunfs/root/main:2:47)
at <anonymous> (/$bunfs/root/main:214:40)
at <anonymous> (/$bunfs/root/main:2:47)
at /$bunfs/root/main:385:30
at loadAndEvaluateModule (1:11)
at moduleEvaluation (1:11)
at loadAndEvaluateModule (2:1)
If you do not receive this error, try running the file from another directory: cd .. ; myproject/myExecutable
Note: Depending on the Bun version and the system, you might receive an error from Bun (not from the library). However, as far as I could investigate, this error only occurs when the program finishes, and all the code actually did run successfully.
Version
5.1.7
Node.js Version
Bun 1.2.23
How did you install the library?
bun add, npm install, and npm install from source code
When installed through npm, prebuild will automatically download and fetch the precompiled binaries, it does however need to pick the right CPU architecture.
When installed through npm, prebuild will automatically download and fetch the precompiled binaries, it does however need to pick the right CPU architecture.
Actually, the problem isn’t related to fetching the binaries — with Bun, you do get the .node binary file according to the architecture.
The real issue is that the require call made by the bindings package happens at runtime, and Bun’s compiler can’t properly do its magic (since it can’t predict where the require will point). Therefore, the resolution of that require depends entirely on the package existing in an exact path relative to where it’s executed at runtime. This means that running the binary inside the project folder might work, but running it outside won’t — which defeats the purpose of having a single standalone binary.
I thought of two solutions. The first one is not very elegant but should work and is easy to apply. The bindings package (which is very small — just one file with ~200 lines of code) basically loops through a predefined array of all possible binary paths using a try/catch. We could simply do the same, but instead of looping, we can manually try/catch each possible path directly in sqlite3-binding.js, and only when running under Bun (otherwise, it would use the normal require via binding). This should give Bun’s compiler enough information to properly attach and resolve the NAPI require.
The second solution is more specific and elegant but would likely require adding a small section to the README. Bun has a feature called preloads that allows running code before the project starts. In theory, we could use a preload script to handle how the require is resolved. However, I’m not sure about the implementation details — whether it can work automatically or if users would need to do some extra setup when using bun build --compile. Because of that, I think the first solution is more viable.
Anyway, if you’d like and give me permission, I’m willing to draft a proposal, test it in different contexts, and make a PR.
Activity
kewde commentedon Oct 7, 2025
How would it select platforms? e.g x86 vs arm?
When installed through npm,
prebuildwill automatically download and fetch the precompiled binaries, it does however need to pick the right CPU architecture.kelvinauta commentedon Oct 7, 2025
Actually, the problem isn’t related to fetching the binaries — with Bun, you do get the .node binary file according to the architecture.
The real issue is that the require call made by the bindings package happens at runtime, and Bun’s compiler can’t properly do its magic (since it can’t predict where the require will point). Therefore, the resolution of that require depends entirely on the package existing in an exact path relative to where it’s executed at runtime. This means that running the binary inside the project folder might work, but running it outside won’t — which defeats the purpose of having a single standalone binary.
I thought of two solutions. The first one is not very elegant but should work and is easy to apply. The bindings package (which is very small — just one file with ~200 lines of code) basically loops through a predefined array of all possible binary paths using a try/catch. We could simply do the same, but instead of looping, we can manually try/catch each possible path directly in sqlite3-binding.js, and only when running under Bun (otherwise, it would use the normal require via binding). This should give Bun’s compiler enough information to properly attach and resolve the NAPI require.
The second solution is more specific and elegant but would likely require adding a small section to the README. Bun has a feature called preloads that allows running code before the project starts. In theory, we could use a preload script to handle how the require is resolved. However, I’m not sure about the implementation details — whether it can work automatically or if users would need to do some extra setup when using bun build --compile. Because of that, I think the first solution is more viable.
Anyway, if you’d like and give me permission, I’m willing to draft a proposal, test it in different contexts, and make a PR.