Databases
We ran each driver against a real server in Docker (Postgres 16, MySQL 8.4, Redis 7) and compared the result with Node 24.
| Driver | 3va 2.9.0 (Postgres rows re-measured on 2.12.1) | Notes |
|---|---|---|
ioredis 5.6 | ✅ Works | |
node:sqlite (built-in) | ✅ Works | Needs read/write grants on the .db file |
pg 8.16, Client | ✅ Works (2.12.1) | SCRAM-SHA-256 fixed; md5/trust always worked |
pg 8.16, Pool | ✅ Works (2.12.1) | Failed on 2.9.0/2.12.0 (stream.ref is not a function) |
postgres (postgres.js) 3.4 | ⚠️ Works (2.12.1) | sql.end() never resolves |
mysql2 3.14 | ❌ Fails | offset is out of bounds |
mysql 2.18 | ❌ Fails (on Node too) | This old driver doesn’t support MySQL 8’s default auth |
better-sqlite3 12 | ❌ Fails | Its binary comes from a shell install script, which 3va refuses even when allowlisted |
drizzle-orm + pg | ❔ Not re-measured | Uses pg.Pool, which works in 2.12.1 |
Permissions
A database client needs a network grant for the database host, plus env access for the connection string:
3va run app.js --allow-read=./node_modules --allow-net=db.internal --allow-env=DATABASE_URLA bare host allows every port; --allow-net=db.internal:5432 limits the
driver to that port. Raw TCP connections check host:port the same way
fetch does.
For SQLite, grant the database file (and its -wal/-shm siblings if you
use WAL mode):
3va run app.js --allow-read=./app.db --allow-write=./app.dbPostgres
Measured on 3va 2.12.1 against Postgres 16 (SCRAM-SHA-256, the default), with
pg and postgres from npm:
| Driver | Result on 2.12.1 |
|---|---|
pg, Client | ✅ Connects with SCRAM and queries |
pg, Pool | ✅ Reusing connections works (3 queries in a row) |
postgres (postgres.js) | ✅ Connects with SCRAM and queries; ⚠️ await sql.end() never resolves, so call process.exit() when you are done |
Earlier versions failed here. On 2.9.0, SCRAM broke with
importKey: unsupported format/algorithm: raw/PBKDF2 (pg) or
SASL_SIGNATURE_MISMATCH (postgres.js), because crypto.pbkdf2Sync(...),
createHash().digest() and createHmac().digest() returned a bare Uint8Array
whose .toString("hex") is a comma-separated list. And pg.Pool threw
this.stream.ref is not a function on its first query. Both are fixed in
2.12.1 (importKey("raw") for PBKDF2/HMAC worked from 2.12.0). On older
versions use a Client against a server with md5 auth, or stay on Node.
MySQL
mysql2 connects but fails on the first query with
offset is out of bounds (a Buffer issue). The older mysql package
fails on MySQL 8’s default auth on Node too, so it’s no alternative.
SQLite
Use the built-in node:sqlite:
const { DatabaseSync } = require("node:sqlite");
const db = new DatabaseSync("./app.db");
db.exec("create table if not exists items(id integer primary key, name text)");
db.prepare("insert into items(name) values(?)").run("from 3va");better-sqlite3, sqlite3 and other native drivers download or compile
their binary in an install script. Even with
"onlyBuiltDependencies": ["better-sqlite3"], 3va refuses that script
because it’s a shell command (prebuild-install || node-gyp rebuild), so
the binary is missing.
ORMs
- Drizzle with
node-postgreshangs because of thepg.Poolbug. - Prisma wasn’t tested. It relies on a native query engine downloaded
at install time and on child processes, so expect the same problem as
better-sqlite3.