Repo of the Day
gajus/slonik: A Node.js PostgreSQL client with runtime and build time type safety, and composable SQL.
Published: Aug 30, 2026
Open repository ↗A Node.js PostgreSQL client with runtime and build time type safety, and composable SQL. - gajus/slonik
Summary
Slonik is a Node.js PostgreSQL client written in TypeScript that wraps node-postgres and adds runtime validation, static type safety, and safety rails around pooling and transactions. It enforces raw SQL through a sql tagged template literal — plain string queries throw — and supplies composable helpers for the dynamic parts.
What it is useful for
Slonik fits when you want PostgreSQL from Node.js without losing type safety or hitting common pooling bugs:
- Built-in result assertions on helper methods such as
oneFirst,one,many,maybeOne,anyFirst,exists, andrecord.oneFirstthrowsNotFoundErroron zero rows andDataIntegrityErroron multiple rows or columns. - Compile-time checks: a
many(...)result (an array) will not type-check when passed to a query expecting a primitive binding, as shown in the README's example. - Safe connection and transaction lifecycles. Connections are checked out only inside a
pool.connect()callback and transactions only insideconnection.transaction(), so a thrown query cannot leak the resource. - Composable SQL fragments via
sql.identifier,sql.join,sql.list,sql.unnest,sql.array,sql.json,sql.jsonb,sql.and,sql.or,sql.unsafe, andsql.fragment, so column lists and filters stay parameterized. - Runtime row validation through a result-parser interceptor, middleware/interceptors, detailed logging, async stack traces, query and transaction retry, and mapped error types such as
CheckIntegrityConstraintViolationErrorandStatementTimeoutError.
A documented trade-off: by default Slonik runs DISCARD ALL after each connection release. The README notes this is a heavy operation and shows how to disable it via resetConnection.
How engineers can use it
The README's entry point is createPool with a DSN such as postgresql://user:pass@host:5432/db plus a clientConfiguration. Imports shown in the README pull from both slonik and @slonik/pg-driver:
import { createPool, sql } from "slonik";
import { createPgDriverFactory } from "@slonik/pg-driver";
const pool = await createPool("postgres://", {
driverFactory: createPgDriverFactory(),
});
Queries must use the sql tag. A type alias describes row shape so helpers can assert and type results:
const id = await pool.oneFirst(sql.typeAlias("id")`
SELECT id FROM foo WHERE bar = ${bar}
`);
Pooled connections and transactions follow the callback pattern:
pool.connect(async (connection) => {
await connection.transaction(async (tx) => {
await tx.query(sql.typeAlias("void")`INSERT INTO foo (bar) VALUES ('baz')`);
});
});
clientConfiguration.password accepts an async callback for IAM-based auth (AWS RDS, GCP Cloud SQL, Azure AD). Caveats from the source: the license field is NOASSERTION, only a subset of libpq DSN options is documented, and pool.end() does not terminate active connections or transactions. See the README for the full API, interceptor configuration, and recipes like bulk inserts and vector data.