Slonik: a Node.js PostgreSQL client that validates rows at runtime and guards against unsafe connection handling
A Node.js PostgreSQL client with runtime and build time type safety, and composable SQL.
At a glance
- What is it?
- Slonik is a TypeScript-first PostgreSQL client for Node.js built around raw SQL, runtime row validation and guards against leaked connections. It suits teams that want SQL in the source, not a query builder, and it costs you a schema library at every query boundary.
- Who is it for?
- Adopt Slonik if your team already writes SQL by hand and wants row shapes checked at runtime rather than trusted from a generated client. Skip it if you need a query builder, an ORM with migrations and relations, or a driver that hides SQL behind method calls; the README's own comparisons cover pg, pg-promise and postgres.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- gajus/slonik4,937 ★ · -5
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| gajus/slonik | 4.9k | 4.9k |
-5 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The problem Slonik solves: SQL you can read, rows you can trust
Most Node.js PostgreSQL code fails in one of two places. Either the SQL is assembled by a query builder and nobody can tell what will reach the server, or the SQL is plain and the row shapes are a guess. Slonik takes a position on both. Its stated principles are that it "promotes writing raw SQL" and "discourages ad-hoc dynamic generation of SQL", and the README links an essay titled Stop using Knex.js to make the case against builders. The audience is a team that is comfortable with PostgreSQL and uncomfortable with an abstraction between the two.
The second half is runtime validation. TypeScript types vanish when the process starts, so a column that changes from text to jsonb, or a join that starts returning nulls, is invisible until something downstream breaks. Slonik lets you attach a schema to a query and check each row as it comes back, which turns a silent shape change into an error at the call site. That is the trade: you keep the SQL, and you pay for a parser on the results.
How the sql tag, the pool and the interceptors fit together
The central object is a connection pool created from a DSN. Queries are written with the sql template tag, and values are interpolated as placeholders rather than concatenated, which is the mechanism behind the README's "safe value interpolation" claim. The tag is composable: sql.fragment, sql.identifier, sql.join, sql.array, sql.json, sql.jsonb, sql.unnest and friends let you build a statement out of typed pieces without ever pasting a string into the query. sql.unsafe exists for the cases where you accept that risk deliberately.
Around the pool sit the guards. The README frames these as protection against unsafe connection handling and unsafe transaction handling. Transactions nest, emit events, and can be retried, and individual queries can be retried too.
Interceptors are the extension point. They wrap query execution, and the repository ships separate packages for this: slonik-interceptor-query-cache is published from the same monorepo, alongside @slonik/sql-tag. The result parser interceptor is the one that powers sql.type, which is how a schema library gets attached to a query. Errors are mapped into named classes such as NotFoundError, UniqueIntegrityConstraintViolationError, ForeignKeyIntegrityConstraintViolationError, StatementTimeoutError and BackendTerminatedError, so a catch block can distinguish a missing row from a dead connection without parsing the driver's message text.
Installing Slonik and running a first validated query
The package is published to npm as slonik. The README documents creating a pool from a connection URI and ending that pool when the process shuts down, and it documents describing the current state of the pool.
The runtime validation penalty and the shape of the schema dependency
Slonik does not ship its own validation language. The README's runtime validation section names a result parser interceptor and shows sql.type, and the tips section discusses compiling Zod schemas at build time, hoisting them with babel-plugin-zod-hoist, and validating queries with eslint-plugin-slonik. In practice that means adopting Slonik usually means adopting a schema library next to it, and the README has a section titled "Performance penalty" that acknowledges the cost of parsing every row. For a dashboard query returning a handful of rows this is noise. For a bulk export returning hundreds of thousands, per-row validation is a real expense, and the sensible move is to validate the queries where a shape change would be dangerous and leave the bulk paths untyped.
There is a second, quieter cost. The README documents behaviour for unknown keys in validated results, and that behaviour is a policy decision you inherit: a column added to a table may or may not break a query depending on how the schema is written. Teams that expect additive migrations to be free should read that part before writing their first schema.
Where Slonik is the wrong tool
Slonik is a client, not a data layer. The README points readers to a separate Migrations section rather than presenting migrations as a core feature. If your application is mostly CRUD over a schema you would rather not think about, an ORM will produce working code faster, and Slonik's insistence on hand-written SQL will read as friction rather than discipline.
Finally, the repository is a pnpm workspace with packages split across types, utilities, errors, sql-tag, driver, pg-driver and slonik, and the release notes show packages versioned in lockstep (@slonik/[email protected], [email protected] and @slonik/[email protected] on 2026-10-24). That is a large surface for a database client, and pinning versions across the set is part of the upgrade work.
Slonik against pg, pg-promise and postgres
The README has a section on each of these comparisons. Against pg, the underlying driver, the difference is everything Slonik adds on top: placeholders through the sql tag, cardinality-specific query methods, connection and transaction guards, interceptors and mapped error classes. Plain pg gives you a client and a pool and leaves those decisions to you.
Slonik's distinguishing additions are the runtime row validation through sql.type and the interceptor pipeline; pg-promise's model centres on its own formatting and helpers. The choice comes down to whether you want a schema library in the query path.
Against postgres, often referred to as postgres.js, the split is similar in shape but different in emphasis. The postgres package is known for its own template-tag API; Slonik's pitch is the validation layer, the assertion helpers and the error taxonomy.
Maintenance, releases and the licence question
The repository is not archived, and the last push was on 2026-10-24. Releases are managed with Changesets, and the recent release list shows packages published together at version 49.12.0. The monorepo uses pnpm workspaces, with linting split across knip, oxlint and oxfmt, and a Husky directory for git hooks; the root package.json exposes lint:knip, lint:oxlint and lint:oxfmt behind a single lint script. For an adopter, the practical upgrade cost is that the version number is shared across the packages you install, so a bump touches the core and any interceptor or sql-tag package at the same time.
The licence is the loose end. The repository metadata reports NOASSERTION rather than a recognised identifier, even though a LICENSE file exists at the root. This is not legal advice, but before shipping Slonik in a product you should open that file and read the actual terms rather than trusting the package metadata, and check whether the satellite packages carry the same terms.
Editorial conclusion
Adopt Slonik if your team already writes SQL by hand and wants row shapes checked at runtime rather than trusted from a generated client. Skip it if you need a query builder, an ORM with migrations and relations, or a driver that hides SQL behind method calls; the README's own comparisons cover pg, pg-promise and postgres. Before committing, check the LICENSE file at the repository root, since the package metadata reports NOASSERTION rather than a named licence, and confirm that your Node version and your chosen schema library are supported by the current release line.
Frequently asked questions
What does slonik mean?
The README has a section titled Origin of the name; read that section in the repository for the author's explanation.
How does Slonik compare with pg?
The README includes a pg vs slonik section. Slonik is built on top of a driver and adds the sql template tag for safe value interpolation, cardinality-specific query methods, connection and transaction guards, interceptors and mapped error classes.
How does Slonik compare with TypeORM?
The README compares Slonik with pg, pg-promise and postgres, and does not cover TypeORM. What can be said from the README is that Slonik promotes writing raw SQL and discourages ad-hoc dynamic generation of SQL, which is a different approach from an entity-based ORM.
How does Slonik compare with postgres.js?
The README has a postgres vs slonik section. Slonik's stated features centre on runtime validation, assertions and type safety, safe connection and transaction handling, interceptors and mapped errors.
what does slonik mean
The README's Origin of the name section is the place the author addresses it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gajus-slonik)Star history chart for your README
[](https://hysenlabs.com/projects/gajus-slonik)Was this useful?