- Methods on Postgres tables = your API. No routes. No GraphQL. No auto-CRUD.
- Every Postgres function, fully typed. All 77 base types, every operator, nullability tracked at the type level.
- Clients compose typed SQL across the wire. Server validates the surface area you expose.
- Live by default.
.live()re-queries when the underlying data changes — pushed directly to clients.
Developer preview — surface is settled, edges still being filed. Not yet recommended for production.
npm install typegres pgimport { typegres, Int8, Text, expose } from "typegres";
const db = await typegres({
type: "pg",
connectionString: process.env.DATABASE_URL!,
});
class Users extends db.Table("users") {
@expose() id = (Int8<1>).column({ nonNull: true, generated: true });
@expose() first_name = (Text<1>).column({ nonNull: true });
@expose() last_name = (Text<1>).column({ nonNull: true });
// Derived column — composes back into your typed query API.
@expose() fullName() {
return this.first_name["||"](" ")["||"](this.last_name);
}
}
// `fullName()` works anywhere a column does — select, where, orderBy:
const rows = await Users.from()
.select(({ users }) => ({
id: users.id,
name: users.fullName(),
}))
.execute(db);
console.log(rows);
await db.close();For a complete scaffold with migrations + codegen, see
examples/basic. Or try it interactively at
typegres.com/play.
- Types codegen'd from the Postgres catalog. 77 base types, full method/operator coverage, nullability tracked at the type level.
- Object-capability queries. Clients can only reach what you've exposed
as
@exposemethods — columns, relations, scoped reads, mutations. The class surface is the contract; the schema underneath is free to move. - Object-capability RPC. The query builder ships to a constrained
interpreter on the server; only
@expose-marked methods reach evaluation. - Live queries.
.live()watches the predicates your query depends on and re-yields when committed mutations would change the result.
Deeper dive in docs/ARCHITECTURE.md.
- Full pg type system + operator/function codegen
- Query builder (
.select+.join+.where+.groupBy+.having+.orderBy+.limit) - Mutations (
.insert/.update/.delete/.returning) - Subqueries, scalar/array aggregation
- Table codegen from live schema
- Live queries —
.live()returns an async iterable that re-yields when committed mutations would change the result - Capability-rooted RPC — closures composed against
@expose-marked classes/methods are serialized, evaluated server-side under a constrained interpreter, and JSON-streamed back
- SQLite backend (sql-builder is dialect-aware; adapter is stubbed)
-
pg_notify-driven live updates (currently a single shared polling loop, not per-subscription) - WAL-mode for live updates (currently uses an auxiliary table)
- Cap'n Web transport (in-flight upstream PR; cloudflare/capnweb#162)
Recommended: Nix the package manager
- direnv. The
.envrc(use flake) auto-activates the pinned toolchain when youcdinto the repo, andbin/startpgworks out of the box. Without Nix, pointDATABASE_URLat any local Postgres and skipstartpg.
./bin/startpg # one-time dev Postgres socket (Nix)
npm install
npm run check # lint + typecheck + testsMIT — see LICENSE.
