Getting started
Build dbSDK from a local clone, pick an adapter, and run your first parameterized query.
dbSDK is not on npm yet. This guide installs it from the GitHub repository instead: clone, build the package, and point your app at the build output. Everything after that is the same on every adapter.
1. Build from source
git clone https://github.com/pkyanam/dbSDK.git
cd dbSDK
pnpm install
pnpm --filter dbsdk build
The build emits packages/dbsdk/dist with the entrypoints you will import:
dbsdk (core), plus the adapter subpaths dbsdk/postgres,
dbsdk/supabase, dbsdk/neon, and dbsdk/testing.
Then bring the package into your app in one of two ways.
Link the built package (fastest for local development):
# from your app directory
npm install /absolute/path/to/dbSDK/packages/dbsdk
Or pack a tarball:
cd packages/dbsdk
npm pack # produces dbsdk-0.1.0.tgz
cd -
npm install ./packages/dbsdk/dbsdk-0.1.0.tgz # from your app directory
Driver requirements. The two database drivers are optional peer dependencies, installed only where you use them:
| Adapter subpath | Driver to install | Used for |
|---|---|---|
dbsdk/postgres |
pg |
any PostgreSQL endpoint over TCP |
dbsdk/supabase |
pg |
Supabase Postgres connections |
dbsdk/neon |
@neondatabase/serverless |
Neon HTTP, WebSocket, and TCP transaction transports |
dbsdk itself and dbsdk/testing pull in no database driver, so bundling
the core does not bundle a driver you do not use.
2. Pick an adapter and connect
Each adapter wraps the service you already have. You need one connection string from that service’s dashboard; nothing is provisioned for you.
import { createDatabase } from "dbsdk";
import { neon } from "dbsdk/neon";
const db = createDatabase({
adapter: neon({
connectionString: process.env.DATABASE_URL!,
transport: "http", // the default
}),
});
The same client shape works for every adapter; only the adapter import and its options change. See the adapter pages for the exact options:
- Postgres: any PostgreSQL endpoint over TCP.
- Supabase: explicit
connectionMode(direct,session,transaction). - Neon:
transport(http,websocket) and an optionaltransactionTransport.
Keep connection strings in environment variables on the server. dbSDK never logs them and never puts them in error messages.
3. Run a query
Interpolated values become positional bind parameters. They can never become identifiers or fragments of SQL text.
const { rows, rowCount, command } = await db.sql`
select id, email from users where id = ${userId}
`;
// rows: Record<string, unknown>[] unless you annotate the result, e.g.:
// const typed: QueryResult<{ id: string; email: string }> = await db.sql`...`
// rowCount: number | null
// command: "SELECT" (the PostgreSQL command tag, when reported)
Every adapter returns that same envelope, on every transport. A write looks like this:
const result = await db.sql`
insert into users (email) values (${"ada@example.com"})
returning id
`;
result.rowCount; // 1
Dynamic identifiers are the one thing interpolation must not do, so they have their own validated escape hatch:
import { sql } from "dbsdk";
await db.query(sql`select * from ${sql.identifier(tableName)} limit 10`);
4. Close the connection
close() is idempotent, and every operation after it fails before dispatch.
For serverless functions, prefer explicit disposal so the pool shuts down
before the invocation returns. The disposal protocol is available in two
ways depending on your Node version:
// Node 24+: await using is supported syntax
await using db = createDatabase({ adapter: neon({ connectionString }) });
// closed automatically at the end of the scope
// Node 22 (engines require >=22.12): explicit close
const db = createDatabase({ adapter: neon({ connectionString }) });
try {
// ... queries
} finally {
await db.close();
}
// or: await db[Symbol.asyncDispose]() at the end of the scope
5. Next steps
- What each transport supports: Capabilities
- Writing queries and building reusable statements: Queries
- Transactions and batches: Transactions
- Working without credentials: Testing
- Runnable programs in the repository:
examples/