Skip to content

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.

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:"-".

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.

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.

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.