Declaring models
A model is an exported Go struct: LiteORM’s orm front-end maps its fields to columns from the field types and orm:"..." (or gorm:"...") struct tags. This page is the reference for that mapping — the tag grammar, embedded structs, and how the table name is chosen. For the specifics of composite keys, naming conventions, and indexes, follow the links at the end.
For exhaustive API detail, see the reference at pkg.go.dev/liteorm.org/orm.
A struct is a table
Section titled “A struct is a table”Each exported scalar field becomes a column; the field’s Go type picks the SQL type via the dialect. Relation fields (a struct, pointer-to-struct, or slice of another model) are not columns — they’re associations, resolved separately. With no tag, the column name is the snake_case of the field name, so AuthorID maps to author_id and CreatedAt to created_at.
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" }An unexported field is ignored entirely. To skip an exported field, tag it orm:"-".
The tag grammar
Section titled “The tag grammar”An orm tag is a comma-separated list: the first token is the column name (leave it empty to keep the snake_case default and still pass options, e.g. orm:",unique"), and the rest are options. Gorm tags use the ;-separated key:value form and are read natively, so an existing gorm model needs no changes.
| Tag option | Effect |
|---|---|
col_name (first token) |
override the column name |
pk |
primary key |
autoincrement |
auto-increment the key |
noauto |
suppress the auto-increment a bare integer PK gets by convention |
unique |
unique constraint / index on the column |
notnull |
NOT NULL |
default:X |
column default X |
size:N |
column size hint (e.g. varchar length) |
type:T |
explicit SQL column type, overriding the dialect default |
check:EXPR |
a CHECK constraint |
index |
index the column (index:name for an explicit index name) |
autocreatetime |
stamp to now on Create |
autoupdatetime |
stamp to now on Create and Update |
soft_delete |
mark the soft-delete timestamp column (see soft delete) |
codec:name |
run the field through a registered field codec |
readonly |
included in reads, excluded from INSERT/UPDATE |
writeonly |
written but excluded from SELECT column lists |
embedded |
flatten an embedded struct’s columns into this table |
embeddedprefix:p |
prefix the flattened columns of an embed |
m2m:join_table |
many-to-many through the named junction (see associations) |
fk:Field |
override the inferred foreign-key column |
references:Field |
override the referenced key column |
- |
skip this field — not a column |
autocreatetime / autoupdatetime work with time.Time, sql.NullTime, or *time.Time fields and are stamped by the repository. A check: or default: value that contains a comma must use the gorm tag form (gorm:"check:price > 0"), because the orm tag splits on commas.
The index and constraint options (unique, index, notnull, check, foreign keys) are covered in depth, with composite and partial indexes, in indexes & constraints.
Embedded structs
Section titled “Embedded structs”An anonymous embed, or a named field tagged embedded, flattens the inner struct’s columns into the outer table rather than becoming a relation. Use embeddedprefix: to disambiguate columns when you embed the same shape twice:
type Timestamps struct { CreatedAt time.Time `orm:"created_at,autocreatetime"` UpdatedAt time.Time `orm:"updated_at,autoupdatetime"`}
type Address struct { Line1 string City string}
type Order struct { ID int64 Timestamps // anonymous embed → created_at, updated_at Shipping Address `orm:"embedded,embeddedprefix:ship_"` // → ship_line1, ship_city Billing Address `orm:"embedded,embeddedprefix:bill_"` // → bill_line1, bill_city}A named struct field without the embedded tag is treated as an association, not an embed.
The table name
Section titled “The table name”By default the table name is the snake_case of the type name — Post maps to post, not posts (there is no silent pluralization). A TableName() string method on the type always wins:
func (Post) TableName() string { return "posts" }To opt into gorm-style plurals process-wide, call orm.UsePluralTableNames(true) once at startup (and orm.RegisterPlural for irregulars); a per-type TableName() still takes precedence. The naming rules — and how to override each — are detailed in conventions.
Where to next
Section titled “Where to next”- Conventions — table naming, primary-key and foreign-key inference, and their overrides.
- Composite keys — tagging more than one field
pk. - Indexes & constraints —
unique,index,check, and foreign keys in depth. - Field codecs — transform a field on the way to and from the column.
- CRUD with the Repo — reading and writing your models.
- Associations — the relation fields this page skips.