Exact row types
Column names follow Postgres's own naming rules, and nullability follows its semantics, including outer joins, aggregates, COALESCE, scalar subqueries and WHERE clauses that rule out NULL.
Write SQL as a string literal. The compiler parses it and gives you the row type, the parameter types and the schema changes. No codegen, no database connection, no build step.
import { Pool } from "pg";
import { createSql, query } from "@typesql/pg";
import type { DB } from "./schema.js";
const sql = createSql<DB>();
const pool = new Pool({ connectionString: process.env["DATABASE_URL"] });
const recent = sql(
`SELECT u.id, u.email, p.title
FROM users u
LEFT JOIN posts p ON p.author_id = u.id
WHERE u.created_at > $1`,
new Date("2026-01-01"),
);
const rows = await query(pool, recent);
// rows: { id: number; email: string; title: string | null }[]