# pgTyped: the root manifest says 0.0.1 while the tags say v2.4.3

> A generator that turns raw SQL into strictly typed TypeScript by reading your running Postgres database as the source of type information, published as two packages, a CLI and a runtime. The root manifest is a lerna workspace pinned at 0.0.1, type generation needs a live database, and every nullable column comes back as a union with null.

**adelsz/pgtyped** — pgTyped - Typesafe SQL in TypeScript

- Repository: https://github.com/adelsz/pgtyped
- Website: https://pgtyped.dev
- Stars: 3,285 · Forks: 119
- Language: TypeScript
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/adelsz-pgtyped

## The root package.json is a workspace pinned at 0.0.1

The manifest at the top of the repository is not the package you install. Its name is pgtyped, its version field reads 0.0.1, and its main is index.js. It declares workspaces of packages/* and delegates every real task to lerna.

The published versions live in the tags instead: v2.4.3 dated 2025-03-15, v2.4.2 dated 2025-02-10, and v2.3.0 dated 2023-10-07. So a reader checking the version has two sources that disagree by more than two years of numbering, and the one in the tree is the placeholder.

The last push on the default branch is dated 2026-10-02, while the newest tag is from March 2025. The file also states in its own words that the project is being actively developed and that its APIs might change, which is a claim about the project rather than about the tag history.

## Types come from the running database, so the schema is never written twice

The central design choice is stated twice. There is no need to map or translate the database schema into TypeScript, because types and interfaces are generated from the running Postgres database as the source of type information.

That has a consequence worth stating before you try it: generation needs a reachable database. The four getting-started steps install the CLI, install the runtime, create a config.json, and then run the generator in watch mode, and the watch mode is what makes the connection practical, since types are regenerated as queries are written.

The file also points at a preconfigured example app under packages/example for anyone who would rather not build a config from nothing.

## Every nullable column arrives as a union with null

A query written in a SQL file carries its name in a comment:

```sql
/* @name FindBookById */
SELECT * FROM books WHERE id = :bookId;
```

The generated TypeScript names both the parameter and the result:

```ts
/** 'FindBookById' parameters type */
export interface IFindBookByIdParams {
  bookId: number | null;
}

/** 'FindBookById' return type */
export interface IFindBookByIdResult {
  id: number;
  rank: number | null;
  name: string | null;
  author_id: number | null;
}
```

Two things to notice. The star in the query is resolved into four named columns, which means the generator asked the database what the table actually holds. And every column the database allows to be null comes back as a union with null, including the parameter, so a caller passing a number is working against a type that also admits null.

The two interfaces are then handed to a single generated object, declared as a PreparedQuery parameterised by the params type and the result type, and exported under the camel-cased form of the name from the comment. The output file is named after the input, so books.sql produces books.queries.ts.

## Injection safety comes from never substituting a parameter at all

The stated reason is not escaping but separation. Rather than doing explicit parameter substitution, PgTyped sends queries and parameters separately to the database driver, which lets the PostgreSQL server perform the substitution.

The call signature shows the consequence, because the client is passed at the point of execution rather than captured at import time:

```ts
import { Client } from 'pg';
import { findBookById } from './books.queries';

export const client = new Client({
  host: 'localhost',
  user: 'test',
  password: 'example',
  database: 'test',
});

async function main() {
  await client.connect();
  const books = await findBookById.run(
    {
      bookId: 5,
    },
    client,
  );
  console.log(`Book name: ${books[0].name}`);
  await client.end();
}
```

Note that the driver is not a dependency here. The example imports Client from pg, so the database library is the application's choice. Interpolation helpers for arrays and objects are listed among the features, and native ESM support is claimed with the runtime dependencies also shipped as CommonJS.

## Two packages, a config file, and a watch flag

Installation is four lines. The CLI and its peer dependency go in as development dependencies:

```
npm install -D @pgtyped/cli typescript
```

The runtime goes in as a normal dependency:

```
npm install @pgtyped/runtime
```

Then a PgTyped config.json is created, and the generator starts in watch mode:

```
npx pgtyped -w -c config.json
```

The split matters more than it looks. typescript is called out as a required peer dependency of the CLI, and the runtime package is named as the only required runtime dependency, so a project that installs the CLI without the runtime gets a build-time tool and nothing to import.

Queries can be extracted from SQL files or from TypeScript files, and the documentation set has a page for each: writing queries in SQL files, advanced queries and parameter expansions in SQL files, the same two for TS files, and one on configuring the tool.

## npm test runs the linter before it runs a single test

The scripts at the root are short enough to read in one go. test is npm run lint followed by lerna run --stream test, so a formatting or lint failure stops the suite before any test executes. lint is tslint --project tsconfig.json -t verbose, and a second script named lint! re-runs it with a fix flag.

build is lerna run build, watch runs the per-package watch in parallel with streamed output, and clean is rm -r packages/*/lib, a plain recursive remove that assumes a Unix shell rather than a cross-platform one.

The declared engine is Node 18 or newer. A jest.config.ts sits at the root even though the test script delegates to lerna, and the tooling is TSLint with prettier wired in through tslint-plugin-prettier and tslint-config-prettier, alongside their own .prettierrc.yaml and .prettierignore.

## The documentation site is built and deployed from this repository

The homepage is a documentation site, and its source is in the tree. A docs-new/ directory and a vercel.json at the root are what publish it, which means the documentation and the generator are versioned together rather than living apart.

The folder name is the interesting part. It reads docs-new rather than docs, which suggests the current site was built somewhere other than the original documentation location, and the README's resource links all point at the published site rather than at files in the repository.

Dependency updates are automated through renovate.json, and the tree uses package-lock.json rather than another lockfile. The repository also carries a demo.gif and a header.png for the README, a CONTRIBUTING.md, and an MIT LICENSE with the copyright line reading Adel Salakh, 2019 to present. No comparable project is named anywhere, so a reader weighing this against another typed SQL tool has nothing in the file to compare it with.

The root dependency list is short as well: a single runtime dependency, io-ts, plus the development tooling. Everything specific to generating queries lives in the packages directory that lerna fans out over.

## Conclusion

pgTyped fits a team that already writes SQL by hand and wants types without a schema definition layer, and its safety argument is the part worth taking seriously, since parameters never get pasted into query text. Two constraints come with it. Type generation reads a live database, so it belongs in a development step with a reachable Postgres instance rather than in a build that has to work offline. And the version you read in the repository is not the version you install, because the root manifest sits at 0.0.1 while the tags reach 2.4.3, with the last tag dated 2025-03-15 and the last push on the default branch dated 2026-10-02. Before adopting it, check that your driver is one you can pass a client into per query, and read the file's own warning that its APIs may change.

## FAQ

### How do I install pgtyped?

Run npm install -D @pgtyped/cli typescript, since typescript is a required peer dependency, then npm install @pgtyped/runtime, which is the only required runtime dependency. Create a PgTyped config.json and run npx pgtyped -w -c config.json to start it in watch mode.

### Where does pgtyped get the types for my SQL queries from?

From your running Postgres database, which the file calls the live source of type data. There is no need to map or translate the database schema into TypeScript, because types and interfaces are generated for the parameters and results of each query.

### Does pgtyped prevent SQL injection?

By not doing explicit parameter substitution. Queries and parameters are sent separately to the database driver so the PostgreSQL server performs the substitution, and interpolation helpers are provided for arrays and objects.

### What version of pgtyped should I install?

The recent tags are v2.4.3 from 2025-03-15, v2.4.2 from 2025-02-10 and v2.3.0 from 2023-10-07. The version field in the root package.json reads 0.0.1, because that manifest is the lerna workspace root rather than a published package.

### Can I write my queries in TypeScript instead of SQL files?

Yes. Queries are extracted and typed from both SQL and TypeScript files, and the documentation set has a page for writing queries in SQL files, a page for advanced queries and parameter expansions there, and the two matching pages for TypeScript files.

## Sources

- [adelsz/pgtyped on GitHub](https://github.com/adelsz/pgtyped)
- [License: MIT](https://github.com/adelsz/pgtyped/blob/master/LICENSE)
- [Project website](https://pgtyped.dev)
- [README](https://github.com/adelsz/pgtyped/blob/master/README.md)
- [Releases](https://github.com/adelsz/pgtyped/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/adelsz-pgtyped
