Conventions
LiteORM’s orm front-end leans on convention so a plain struct maps to a table with no ceremony — but every convention is one you can reason about, and every one has an explicit override. There’s no silent pluralization, no lazy loading, and an inference that can’t be made is a hard error naming both sides rather than a best-effort guess. This page lists the mapping rules and how to override each.
For exhaustive API detail, see the reference at pkg.go.dev/liteorm.org/orm.
Table naming
Section titled “Table naming”By default the table name is the snake_case of the type name — Post maps to post, UserProfile to user_profile. LiteORM does not pluralize by default. Override, from most specific to least:
| I want… | Do this |
|---|---|
| one type’s table name set exactly | give it a TableName() string method |
gorm-style plurals process-wide (Post → posts) |
call orm.UsePluralTableNames(true) once at startup |
| an irregular plural the pluralizer misses | orm.RegisterPlural("quiz", "quizzes") |
func (Post) TableName() string { return "posts" } // always winsA per-type TableName() always beats the process-wide setting. UsePluralTableNames applies to both the orm and query front-ends (they share the naming resolver), so call it once before any schema is resolved; RegisterPlural inflects only the last snake_case segment, so register the bare word (person, which also covers blog_person).
Primary keys and auto-increment
Section titled “Primary keys and auto-increment”A field named ID (column id) is the primary key by convention. An integer primary key is treated as auto-increment — the database assigns it and Create reads the generated value back into your struct. Override:
| I want… | Do this |
|---|---|
| a different column as the key | tag it orm:"pk" |
a non-id field named the key |
tag it orm:",pk" (or give it column id) |
| force auto-increment on a key | tag it orm:"autoincrement" |
| a caller-assigned integer key (no auto-increment) | tag it orm:"pk,noauto" |
| a key spanning several columns | tag each field orm:"pk" — see composite keys |
A composite key is never auto-increment: its parts are yours to assign. Schema.PK is the single-key convenience (nil for a composite key); Schema.PKs is always the full, ordered list.
Foreign-key naming
Section titled “Foreign-key naming”For an association, the foreign key is inferred by convention as <type>_id in snake_case, on whichever side owns the key — a belongs-to puts <target>_id on the owner (Post.Author → author_id on Post), and a has-many or has-one puts <owner>_id on the target (Author.Posts → author_id on Post). A key that can’t be found is a hard error naming the column it looked for. Override with tags on the relation field:
type Post struct { ID int64 Author *Author `orm:"fk:writer_id"` // FK column is writer_id, not author_id Editor *Author `orm:"fk:editor_id,references:ID"` // and the key it references}fk: names the foreign-key column, references: names the referenced key column. The referenced column defaults to the target’s primary key. (These tags are read against whichever side owns the key.)
Soft-delete column detection
Section titled “Soft-delete column detection”A model becomes soft-delete-aware when it has a field tagged soft_delete — conventionally a sql.NullTime named DeletedAt:
DeletedAt sql.NullTime `orm:"deleted_at,soft_delete"`There is no naming magic here — the tag is the switch, so the column can be called anything. Its presence turns Delete into an UPDATE, excludes deleted rows from reads by default, and makes AutoMigrate build unique indexes as partial indexes scoped to live rows. To make a model not soft-delete-aware, leave the tag off. The full behavior — the tri-state read scopes, ForceDelete, Restore — is in soft delete.
Timestamp columns
Section titled “Timestamp columns”autocreatetime and autoupdatetime opt a time.Time, sql.NullTime, or *time.Time field into automatic stamping — created-time on Create, updated-time on Create and Update. These are explicit tags, not name-based magic; a field named CreatedAt does nothing special until you tag it:
CreatedAt time.Time `orm:"created_at,autocreatetime"`UpdatedAt time.Time `orm:"updated_at,autoupdatetime"`Where to next
Section titled “Where to next”- Declaring models — the full tag grammar these conventions sit under.
- Composite keys — keys spanning more than one column.
- Associations — the foreign-key inference in practice.
- Soft delete — what the
soft_deletetag turns on. - Migrations — how AutoMigrate emits the schema these rules describe.