A schema-reconciling PostgreSQL mapper for Go
You own your structs.PostgreSQL owns your schema.The generator proves they agree.
Neither representation is generated from the other. You write the structs; migrations own the schema. The orm command introspects both, reports every place they disagree, and generates typed metadata only from a mapping it proved.
// The type parameters are the point: a Predicate[User] cannot
// reach a query over Post, and a NOT NULL column has no IsNull.
users, err := db.Users.Query().
Where(Users.Email.ILike("%@example.com")).
Where(Users.CreatedAt.Gte(cutoff)).
With(Users.Orders.OrderBy(Orders.Placed.Desc()).Limit(5)).
OrderBy(Users.CreatedAt.Desc()).
Limit(50).
All(ctx)What the compiler catches
Types come from the catalog
A column's Go type is what PostgreSQL says it is. A text column has Like and an integer does not; a NOT NULL column has no IsNull. None of it is a convention you have to remember.
Nullability is a property of the query
A NOT NULL column read through an outer join can still be NULL, so it widens. A select list that ignores that is refused at build time, not discovered as a scan error on the row that happened not to match.
Relations are asked for, never guessed
There is no lazy loading, so a loop over a slice cannot become a query per row. Loading is breadth-first and batched: the statement count follows the shape of the tree you asked for, never the number of rows in it.
Migrations are planned and proved
Declarations are diffed against the schema the migrations describe. Destructive changes are gated, materialized views have a safe lifecycle, and the artifacts are portable across every supported major.
One statement, always
Composition, CTEs, derived tables and UNION ALL compile through one AST and one writer, with one global placeholder namespace. Nothing is assembled from strings and nothing is stitched together in Go.
PostgreSQL's own types survive
Ranges keep their bound model, intervals keep months and days apart, and uuid, jsonb, arrays and PostGIS geometry stay themselves rather than being reduced to something Go already had.
Proved, not asserted
Every frozen milestone carries a mutation campaign: the code is deliberately broken and the suite has to notice. The compatibility matrix refuses to run against fewer than the five PostgreSQL majors the project claims.
- 14–18
- PostgreSQL majors
- 56
- mutation classes caught
- 0
- survivors