Getting started
LiteORM gives you two ways to talk to a database, sharing one core. The query front-end is explicit and generics-first — you write the shape of the query and get typed rows back. The orm front-end is declarative — you describe a model with struct tags and get CRUD, associations, hooks, soft-delete, and migrations. They interoperate: both take a liteorm.Session (a database handle or a transaction), so a value fetched one way feeds the other on the same transaction.
Using an AI coding assistant? LiteORM ships Agent Skills that give your assistant the exact, current API for each task, so it writes correct LiteORM the first time. Setting them up is the highest-leverage few minutes here — see AI agents & skills.
Install
Section titled “Install”Add the core plus the backend you want. The core (liteorm.org) pulls in zero database drivers; each backend is its own module, so your dependency graph only carries the driver you actually use.
go get liteorm.orggo get liteorm.org/dialect/sqlite # CGo-free SQLite (via gosqlite.org)# or: liteorm.org/dialect/postgres · liteorm.org/dialect/mysql · liteorm.org/dialect/mssqlOpen a database
Section titled “Open a database”A backend’s Open returns a *liteorm.DB, which is a liteorm.Session — the handle both front-ends accept.
import "liteorm.org/dialect/sqlite"
db, err := sqlite.Open("app.db") // WAL + sensible pragmas appliedif err != nil { log.Fatal(err)}defer db.Close()Other backends open from a DSN (Postgres uses the native pgx protocol):
import "liteorm.org/dialect/postgres"
db, err := postgres.Open(ctx, "postgres://user:pw@localhost/app?sslmode=disable")See Backends for every DSN shape.
Your first query
Section titled “Your first query”The query front-end builds a typed SELECT over a model type. A model is any struct; a TableName() method (or the snake_case of the type name) names the table.
import "liteorm.org/query"
type Product struct { ID int64 Name string Category string Price float64}
func (Product) TableName() string { return "products" }
// Typed predicates, validated against the model's columns at build time.hits, err := query.Select[Product](db). Filter(query.And( query.Col[string]("category").Eq("books"), query.Col[float64]("price").Lt(40), )). OrderBy("price"). All(ctx)CRUD lives on a Repo:
repo := query.NewRepo[Product](db)p := Product{Name: "Go in Practice", Category: "books", Price: 39.50}_ = repo.Insert(ctx, &p)got, err := repo.Get(ctx, p.ID) // returns liteorm.ErrNoRows if absentMore — joins, unions, subqueries, streaming, upserts, bulk insert — in the query guide.
Your first model
Section titled “Your first model”The orm front-end is declarative. Tag the struct, migrate it, and use the Repo.
import "liteorm.org/orm"
type Author struct { ID int64 Name string Email string `orm:"email,unique"`}
func (Author) TableName() string { return "authors" }
_ = orm.AutoMigrate[Author](ctx, db) // additive: creates the table + indexes
authors := orm.NewRepo[Author](db)ada := Author{Name: "Ada", Email: "ada@example.com"}_ = authors.Create(ctx, &ada)Most apps have several models. Migrate them all in one call, in dependency order (referenced tables first) — the same additive guarantees apply:
_ = orm.AutoMigrateAll(ctx, db, Author{}, Book{}, Review{})From here: associations (with N+1-safe eager loading), hooks, soft delete, and migrations.
Transactions and interop
Section titled “Transactions and interop”db.Begin(ctx) returns a transaction that is also a Session. Pass it to either front-end; a nested Begin is a savepoint.
tx, _ := db.Begin(ctx)_ = orm.NewRepo[Author](tx).Create(ctx, &Author{Name: "Grace", Email: "grace@example.com"})back, _ := query.Select[Author](tx).Filter(query.Col[string]("name").Eq("Grace")).First(ctx)_ = tx.Commit(ctx)Details in Transactions.
Errors are normalized
Section titled “Errors are normalized”Constraint and not-found errors map to the same sentinels on every backend, so you write the check once:
if errors.Is(err, liteorm.ErrUniqueViolation) { /* ... */ }if errors.Is(err, liteorm.ErrNoRows) { /* ... */ }See Errors.
Where to go next
Section titled “Where to go next”- Cheat sheet — the whole API surface on one screen, and Recipes for common tasks.
- Coming from gorm — the verb-for-verb map and the intentional differences.
- The query and orm guides cover each front-end in depth.
- Code generation adds compile-time column safety and SQL→Go.
- Backend-specific power: SQLite search, SQLite changesets, Postgres LISTEN/NOTIFY + JSONB.
- Runnable programs live under
examples/;just example <name>runs one,just examplesruns them all. - AI agents & skills — point your AI assistant at the shipped skills so it writes correct LiteORM without guessing.