@runlot/pg
A node-postgres-style Pool and Client API built on env.db. No connection string required.
If you want an API closer to node-postgres than env.db, use @runlot/pg.
import { Pool } from "@runlot/pg";
export default {
async fetch(req: Request, env: Env): Promise<Response> {
const pool = new Pool({ db: env.db });
const { rows } = await pool.query("select id, name from users where id = $1", [1]);
return Response.json(rows);
},
};db is the only option you need
new Pool({ db: env.db });
new Client({ db: env.db });There is no host, port, or password to configure. Other option keys are accepted for node-postgres compatibility, but they are unused. Leaving out db produces this error:
@runlot/pg: `db` is missing — create it with new Pool({ db: env.db }).What it provides
pool.query(text, values)— opens a new session per call. Good for single statements.pool.connect()/new Client({ db })— opens one session.BEGIN … COMMIT, prepared statements, andSETsettings persist within that session. Callrelease()orend()when you are done.- Errors are thrown as
DatabaseError, anderr.codecarries the SQLSTATE. types.setTypeParser(oid, fn)lets you change type conversion. The defaults matchpg:timestamptzanddatebecomeDate, whileint8andnumericstay strings.
import { Pool, DatabaseError } from "@runlot/pg";
const pool = new Pool({ db: env.db });
try {
await pool.query("insert into users (email) values ($1)", [email]);
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
return new Response("That email is already registered", { status: 409 });
}
throw e;
}Transactions
const client = await pool.connect();
try {
await client.query("begin");
await client.query("update accounts set balance = balance - $1 where id = $2", [100, 1]);
await client.query("update accounts set balance = balance + $1 where id = $2", [100, 2]);
await client.query("commit");
} catch (e) {
await client.query("rollback");
throw e;
} finally {
client.release();
}pool.query() uses a new session on every call, so a transaction does not carry across calls. Always use connect() for transactions.
It is called Pool, but it does not reuse connections
Despite the name, Pool does no connection pooling. Every connect() opens a new engine session. See Sessions for why.
Works without nodejs_compat
This package imports no Node built-ins. It uses a minimal emitter instead of EventEmitter, so a worker that only uses this package needs no compatibility flag.
Deploy configuration
Nothing extra to configure. The bundler in runlot deploy resolves pg imports to this package. If your ORM uses Node built-ins, nodejs_compat is enabled automatically, and Prisma's WASM query compiler is included in the manifest as a separate module.
You can use the same bundler if you bundle the worker yourself.
import { buildWorker } from "@runlot/pg/bundler";
const { code, report } = await buildWorker({ entry: "src/index.ts", absWorkingDir: process.cwd() });
// If report.nodeImports is non-empty, nodejs_compat is required.
// report.wasmModules lists the files that must ship with the deploy.