The orm front-end
The orm package is LiteORM’s declarative front-end: you describe your data as plain structs with tags, and a typed repository handles CRUD, associations, lifecycle hooks, soft deletes, and schema migration. It’s convention-driven but never magical — there’s no lazy loading and no silent pluralization, and an ambiguous mapping is a hard error rather than a guess.
It shares one core with the explicit query builder, so a value you fetch through one front-end feeds the other on the same transaction. Reach for orm when you want models, relations, and migrations; reach for query when you want to assemble SQL by hand — see Query or ORM? for the trade-off. For exhaustive API detail, see the reference at pkg.go.dev/liteorm.org/orm.
A model
Section titled “A model”A model is an exported struct. Annotate fields with orm:"..." tags where you need more than the defaults; gorm:"..." tags are read too, so models carried over from gorm work as-is. With no tag, the column is the snake_case of the field, and an int64 field named ID is treated as an auto-increment primary key by convention.
import ( "database/sql" "time"
"liteorm.org/orm")
type Post struct { ID int64 AuthorID int64 `orm:"author_id"` Title string Slug string `orm:"slug,unique"` Views int64 CreatedAt time.Time `orm:"created_at,autocreatetime"` UpdatedAt time.Time `orm:"updated_at,autoupdatetime"` DeletedAt sql.NullTime `orm:"deleted_at,soft_delete"`}
func (Post) TableName() string { return "posts" }The full tag grammar, embeds, and the TableName() rules are in Declaring models.
Migrating the schema
Section titled “Migrating the schema”orm.AutoMigrate[T] brings the table for T into being and keeps it in sync, additively — it creates a missing table with its unique indexes and any junction tables, and adds a column for anything the model gained, but never drops columns or alters types. AutoMigrateAll migrates a whole set in one call (list a referenced table before the table that points at it):
if err := orm.AutoMigrateAll(ctx, db, Author{}, Post{}, Comment{}); err != nil { return err}For reviewable or destructive schema changes see migrations; for the index and constraint tags see indexes & constraints.
First CRUD
Section titled “First CRUD”orm.NewRepo[T](sess) is the typed repository; it runs against a *liteorm.DB or a transaction.
posts := orm.NewRepo[Post](db)
p := Post{AuthorID: ada.ID, Title: "Generics in Go"}err := posts.Create(ctx, &p) // stamps timestamps, reads the generated key back into p
got, err := posts.Get(ctx, p.ID) // by primary key → liteorm.ErrNoRows when absent
p.Views = 42err = posts.Update(ctx, &p)
err = posts.Delete(ctx, &p) // soft delete if the model has a soft_delete column, else hardThe full verb set — Save, Upsert, FirstOrCreate/FirstOrInit, Updates, Select/Omit, batches, and filtered reads — is in CRUD with the Repo.
Where to next
Section titled “Where to next”- Declaring models — structs, the tag grammar, embeds,
TableName(). - CRUD with the Repo — every read and write verb.
- Scopes — reusable, composable read filters.
- Associations — has-many, has-one, belongs-to, many-to-many, eager loading.
- Hooks — typed lifecycle callbacks around writes.
- Soft delete — soft deletes and the tri-state read scopes.
- Conventions — table naming, primary-key and foreign-key inference, and how to override each.
- The query front-end — the explicit builder these models also work with.