Skip to main content
GORM maps Go structs to database tables. Each exported field in a struct becomes a column, and the struct itself maps to a table. GORM reads struct tags in the gorm:"..." namespace to control column names, types, constraints, and behavior.

Basic model definition

A GORM model is any Go struct. GORM will infer the table name and column names from the struct and field names.
type User struct {
    ID        uint
    Name      string
    Email     string
    Age       int
    CreatedAt time.Time
    UpdatedAt time.Time
}
GORM maps this struct to a users table with columns id, name, email, age, created_at, and updated_at.

The gorm.Model embedded struct

gorm.Model is a convenience struct you can embed in your models to get four standard fields automatically.
// From gorm.io/gorm model.go
type Model struct {
    ID        uint `gorm:"primarykey"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt DeletedAt `gorm:"index"`
}
Embed it in your own struct:
type User struct {
    gorm.Model
    Name  string
    Email string
}
This gives the users table the columns id, created_at, updated_at, and deleted_at in addition to name and email.
DeletedAt is a gorm.DeletedAt type (backed by sql.NullTime). When a record is deleted, GORM sets this field to the current time rather than removing the row. Queries automatically filter out soft-deleted rows.

Struct tags

Use the gorm:"..." struct tag to configure field behavior. Multiple options are separated by semicolons.
type Product struct {
    ID          uint   `gorm:"primarykey"`
    Code        string `gorm:"column:product_code;not null;uniqueIndex"`
    Price       float64
    Description string `gorm:"size:1000"`
    Stock       int    `gorm:"default:0"`
}

Primary keys

By default, GORM treats a field named ID as the primary key. If the field is an integer or unsigned integer type, GORM also enables auto-increment.
type User struct {
    ID   uint   // primary key, auto-increment
    Name string
}
To use a different field as the primary key, add the primaryKey tag:
type User struct {
    UserID uint   `gorm:"primaryKey"`
    Name   string
}
To use a non-integer primary key (which disables auto-increment), use a string or uuid type:
type User struct {
    ID   string `gorm:"primaryKey"` // no auto-increment
    Name string
}
Composite primary keys are supported by tagging multiple fields with primaryKey.

Column naming

GORM converts CamelCase field names to snake_case column names by default. The NamingStrategy in schema/naming.go handles common initialisms (such as ID, URL, HTTP) so they don’t produce awkward column names.
Field nameColumn name
Namename
FirstNamefirst_name
UserIDuser_id
APIKeyapi_key
HTTPSPorthttps_port
Override the column name with the column tag:
type User struct {
    Name string `gorm:"column:full_name"`
}

Table naming

GORM pluralizes the struct name in snake_case to derive the table name: Userusers, OrderItemorder_items. Override the table name by implementing the Tabler interface:
type User struct {
    ID   uint
    Name string
}

func (User) TableName() string {
    return "profiles"
}
TableName() must have a value receiver, not a pointer receiver, when used with gorm.DB.AutoMigrate or schema parsing.

Field-level tags reference

Sets the database column name.
Name string `gorm:"column:full_name"`
Sets the SQL column type. Accepts database-specific types.
Bio string `gorm:"type:text"`
Sets the column size/length, primarily for strings.
Username string `gorm:"size:50"`
Adds a NOT NULL constraint to the column.
Email string `gorm:"not null"`
Sets a default value for the column. Can be a literal value or a database function.
Status  string `gorm:"default:active"`
Counter int    `gorm:"default:0"`
Creates a unique index on the column.
Email string `gorm:"uniqueIndex"`
Creates a non-unique index on the column.
LastName string `gorm:"index"`
Marks the field as the primary key.
ID uint `gorm:"primaryKey"`
Enables auto-increment for integer primary keys. Set to false to disable.
ID uint `gorm:"primaryKey;autoIncrement"`
Marks the field as the creation timestamp. Accepts nano or milli to store Unix nanoseconds or milliseconds instead of a time.Time.
CreatedAt int64 `gorm:"autoCreateTime"`       // Unix seconds
CreatedAt int64 `gorm:"autoCreateTime:milli"` // Unix milliseconds
CreatedAt int64 `gorm:"autoCreateTime:nano"`  // Unix nanoseconds
Marks the field as the update timestamp. Same precision options as autoCreateTime.
UpdatedAt int64 `gorm:"autoUpdateTime"`       // Unix seconds
UpdatedAt int64 `gorm:"autoUpdateTime:milli"` // Unix milliseconds
UpdatedAt int64 `gorm:"autoUpdateTime:nano"`  // Unix nanoseconds
Excludes the field from all database operations.
Ignored string `gorm:"-"`            // skip create, read, update
Temp    string `gorm:"-:all"`        // skip everything including migration
NoWrite string `gorm:"-:migration"` // skip migration only
Control field read/write permissions.
ReadOnly  string `gorm:"->"` // read-only
WriteOnly string `gorm:"<-"` // create and update
CreateOnly string `gorm:"<-:create"` // only on insert

Putting it all together

package main

import (
    "time"
    "gorm.io/gorm"
)

type Product struct {
    gorm.Model
    Code        string  `gorm:"column:product_code;size:50;uniqueIndex;not null"`
    Name        string  `gorm:"size:200;not null"`
    Description string  `gorm:"type:text"`
    Price       float64 `gorm:"not null"`
    Stock       int     `gorm:"default:0"`
    SKU         string  `gorm:"column:sku;size:100;index"`
    Internal    string  `gorm:"-"` // not persisted
}

func (Product) TableName() string {
    return "products"
}

Build docs developers (and LLMs) love