Library / SDK
ts-safeql/safeql avatar
ts-safeql/safeql

SafeQL for TypeScript and PostgreSQL Query Validation

Validate and auto-generate TypeScript types from raw SQL queries in PostgreSQL.

1,572 stars37 forksTypeScriptMIT

At a glance

What is it?
SafeQL is an ESLint plugin that infers result types and validates raw PostgreSQL queries in TypeScript projects. It suits teams using SQL directly across multiple clients, but the README provides little information about configuration or query workflows.
Who is it for?
TypeScript teams that write substantial PostgreSQL SQL and already use ESLint can adopt SafeQL after checking its current query coverage and testing it against their client configuration. Projects seeking a database-independent solution, avoiding lint-time PostgreSQL parsing, or needing documented production operations should not assume it fits.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 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 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • ts-safeql/safeql1,572 ★ · +4
Star history
Repository2026-10-172026-11-07
ts-safeql/safeql1.6k1.6k

4 Stars in the last 21 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

SafeQL's PostgreSQL Type Inference Use Case

SafeQL addresses a specific gap between raw SQL and TypeScript. A PostgreSQL client can execute SQL without telling the compiler what columns and result shape the query returns. Developers then face handwritten result interfaces, unsafe casts, or disagreement between an application's declared types and its actual query. The README says SafeQL "automatically infers the type of the query result based on the query itself," so its main purpose is to bring SQL result information into the TypeScript editing and linting process.

The target audience is a TypeScript codebase that uses PostgreSQL queries directly. That includes codebases using pg, Postgres.js, Prisma, Sequelize, or other PostgreSQL clients. SafeQL also presents itself as suitable for monorepos and microservices, particularly projects that work with multiple databases. Those claims describe a fit around PostgreSQL and linting, not a general SQL validator. The project metadata and README consistently limit the implementation to PostgreSQL.

This is useful when SQL remains raw and query results are consumed as typed data in TypeScript. It does not replace the database client, execute queries, or provide a runtime schema layer according to the available documentation. Its role is static analysis through ESLint. Teams should therefore distinguish between checking a query at development time and validating database permissions, constraints, or runtime results in a deployed environment.

ESLint Plugin Architecture and PostgreSQL Parsing

The repository is a pnpm monorepo containing separate packages under `packages/`, documentation under `docs/`, and demonstrations under `demos/`. Its root scripts coordinate package work through Turborepo. The available files also show Changesets for version management, Vitest configuration for tests, and ESLint configuration in `eslint.config.js`. This layout supports a package-based plugin ecosystem rather than a single application.

SafeQL's user-facing package is `@ts-safeql/eslint-plugin`. The documented installation also requires `libpg-query`, which indicates that PostgreSQL query parsing is part of the installation path. The README does not expose the internal parser flow, generated type representation, or exact rule names, so those details cannot be stated reliably. What can be confirmed is that SafeQL operates through ESLint and works with `typescript-eslint` language support.

That design makes lint-time feedback the likely integration point, but "likely" should not be mistaken for documented execution semantics. The root package does define a `lint` script that delegates work across the workspace. For SafeQL consumers, the repository's configured lint tasks belong to the monorepo rather than the installation documentation. It runs the repository's configured lint tasks and should not be presented as a universal initialization command for an application. The installed project still needs its own ESLint and SafeQL rule configuration. The README directs users to the SafeQL getting-started documentation for that missing step.

Installing SafeQL with TypeScript ESLint

SafeQL requires an existing ESLint setup with TypeScript language support. The README links to the `typescript-eslint` Getting Started guide for that prerequisite. Once that setup exists, the documented consumer installation is:

bash
npm install --save-dev @ts-safeql/eslint-plugin libpg-query

This installs the ESLint plugin and its PostgreSQL parser dependency as development dependencies. That placement fits a static analysis tool because the packages support development checks rather than application runtime features. The command uses npm because it is copied from the README, even though this repository itself declares `[email protected]` and contains a pnpm workspace. Users should not mix the consumer command and repository development instructions without checking how their own project manages packages.

A first real query workflow cannot be reproduced from the README alone. It does not show an ESLint configuration, a tagged SQL example, the command used to inspect an individual query, or the generated TypeScript output. The README instead sends readers to `https://www.safeql.dev/guide/getting-started.html`. That documentation is the correct source for the first configuration and query example; inventing either would risk showing a rule name or SQL annotation that SafeQL does not recognize.

After consulting that guide, the concrete local verification is to run the application's existing lint command on code containing one real PostgreSQL query. The expected result is a lint pass without a SafeQL rule failure for that query. The README does not define failure output or explain how unresolved database objects affect analysis.

Client Compatibility and Monorepo Boundaries

SafeQL's compatibility claim is unusually broad within PostgreSQL: the README names Prisma, Sequelize, pg, Postgres.js, and "more." It describes these as PostgreSQL clients and says SafeQL works with them. This suggests the project is intended to avoid forcing one application-side database access pattern, which matters for codebases migrating between clients or using more than one.

That compatibility does not mean SafeQL replaces each client's API or schema model. It addresses TypeScript result typing around raw SQL. The README gives no client-specific configuration, examples, or known incompatibilities, so an engineer cannot determine from the available documentation whether tagged queries behave identically inside Prisma and pg. A prospective adopter should test the exact client and query styles used by the application.

The monorepo claim is more concrete. SafeQL is distributed as packages in a pnpm workspace, with package build, typecheck, test, and lint tasks. The documented monorepo and microservices positioning also connects naturally to multiple database endpoints, but the README does not say how database selection, credentials, schemas, or connection state are represented. No configuration for those concerns is present. SafeQL's static SQL analysis may be used across packages, but whether it understands each package's schema and environment is a separate adoption question.

Limitations of the Available SafeQL Documentation

The largest limitation in the available project documentation is not a stated product boundary, but a documentation gap. SafeQL promises type inference and validation for PostgreSQL queries, yet the README does not show a complete configuration or a before-and-after type example. This makes it difficult to judge which SQL forms are supported, whether nullable expressions are represented precisely, and how joins, aliases, CTEs, or dialect-specific syntax affect inference.

The project is also coupled to a development stack. PostgreSQL is the documented database target, and ESLint with `typescript-eslint` is a prerequisite. Teams that do not run ESLint, do not use TypeScript, or support multiple database engines should not treat SafeQL as a portable query validation layer. The presence of `libpg-query` reinforces the PostgreSQL boundary rather than removing it.

Another unknown is failure behavior. The README does not document rollback, caching, parser timeouts, unavailable database services, or whether linting a query requires a live PostgreSQL connection. It also does not describe runtime result validation. Those omissions do not prove that a feature is absent, but they prevent a production-adoption claim. A first pilot should use a known query whose expected result type is already written by hand, then compare that type with SafeQL's behavior.

SafeQL Versus Handwritten Result Types

The clearest alternative is to keep handwritten TypeScript result interfaces beside raw SQL and let the PostgreSQL client cast or return rows through those declarations. This approach requires no SQL parser during ESLint analysis. Its weakness is manual synchronization: changing a selected column, table function, or expression can leave the TypeScript interface behind unless a separate process updates it.

SafeQL takes a different approach by deriving result information from the query itself. Its advantage is direct alignment between SQL structure and inferred TypeScript types. The trade-off is dependence on SafeQL's supported query syntax, its parser, and the quality of its ESLint integration. Handwritten types add reviewer discipline and repetitive updates; lint-time inference moves that responsibility to tooling.

The two approaches can also coexist during migration. A team can retain explicit interfaces at public boundaries while using SafeQL on internal queries, or compare SafeQL's inferred output against current declarations. The README does not document a command for generating files, so SafeQL should not be described as a general source-code generator. Its confirmed feature is automatic type inference, with validation alongside it.

SafeQL Releases, License, and Upgrade Work

The repository is not archived, and its last push was on 2026-10-13. The recent package releases listed for `@ts-safeql/zod-annotator`, `@ts-safeql/plugin-utils`, and `@ts-safeql/plugin-auth-aws` were published on 2026-06-30. These dates indicate recent repository and package activity, but the README does not provide a support policy or compatibility matrix.

SafeQL is distributed under the MIT license. That identifier permits use, modification, distribution, and sublicensing under the license's conditions, subject to preserving its copyright and license notice. Consumers should retain the applicable notices when installing or redistributing packages. The repository also separates packages into individually versioned releases, so upgrading one package may not imply that every package moves in lockstep.

For contributors and maintainers, upgrade work is package-oriented. The root scripts include `build`, `typecheck`, `test`, `lint`, `publint`, and Changesets-based release commands. The application adopter's upgrade surface is narrower: track `@ts-safeql/eslint-plugin` and `libpg-query`, then rerun lint checks against representative queries. No documented migration command or breaking-change policy appears in the README.

Editorial conclusion

TypeScript teams that write substantial PostgreSQL SQL and already use ESLint can adopt SafeQL after checking its current query coverage and testing it against their client configuration. Projects seeking a database-independent solution, avoiding lint-time PostgreSQL parsing, or needing documented production operations should not assume it fits. The first verification should be a minimal lint run on one real tagged query using the project-specific SafeQL configuration described at safeql.dev.

Frequently asked questions

What is SafeQL used for in a TypeScript project?

SafeQL validates raw PostgreSQL queries and automatically infers their result types. It is intended for TypeScript applications that execute SQL through PostgreSQL clients.

How do I install SafeQL?

First configure ESLint with `typescript-eslint`. Then install `@ts-safeql/eslint-plugin` and `libpg-query` as development dependencies.

Which PostgreSQL clients does SafeQL support?

The README names Prisma, Sequelize, pg, Postgres.js, and other PostgreSQL clients. It does not document client-specific configuration or tested compatibility for each one.

Does SafeQL support databases other than PostgreSQL?

The available documentation describes SafeQL specifically as a PostgreSQL tool and pairs it with `libpg-query`. No support for other database engines is documented.

What license does SafeQL use?

The repository metadata and package configuration identify the project as MIT licensed. License notices and conditions should be retained when redistributing the software.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. ts-safeql/safeql on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ts-safeql-safeql.svg)](https://hysenlabs.com/projects/ts-safeql-safeql)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/ts-safeql-safeql.svg)](https://hysenlabs.com/projects/ts-safeql-safeql)

Was this useful?