Skip to main content
Chainable methods return a new *DB with the additional clause or setting applied. They do not execute any SQL — that happens when you call a finisher method. You can chain as many as you need.
var users []User
db.Where("age > ?", 18).
    Order("name ASC").
    Limit(10).
    Offset(20).
    Find(&users)

Model

func (db *DB) Model(value interface{}) (tx *DB)
Sets the model for the statement. GORM uses the model to infer the table name and schema when no explicit Table is set.
// Update all users (use with care — requires AllowGlobalUpdate or a WHERE clause)
db.Model(&User{}).Update("name", "jinzhu")

// Use the primary key from a loaded struct as a WHERE condition
db.Model(&user).Update("name", "hello")

Clauses

func (db *DB) Clauses(conds ...clause.Expression) (tx *DB)
Adds raw clause.Expression values directly to the statement. Supports standard clauses (clause.OrderBy, clause.Limit, clause.Where), locking hints, and optimizer hints.
// Pessimistic locking
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)

// Optimizer hint (requires the hints package)
db.Clauses(hints.UseIndex("idx_user_name")).Find(&users)

// ON CONFLICT upsert
db.Clauses(clause.OnConflict{
    Columns:   []clause.Column{{Name: "id"}},
    DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)

Table

func (db *DB) Table(name string, args ...interface{}) (tx *DB)
Sets the table name explicitly, bypassing the model-based name inference. Supports raw SQL expressions with args for parameterised table subqueries.
// Plain table name
db.Table("users").Take(&result)

// Schema-qualified table name
db.Table("public.users").Find(&users)

// Subquery as table source
db.Table("(?) AS u", db.Model(&User{}).Select("name, email")).Find(&result)

Distinct

func (db *DB) Distinct(args ...interface{}) (tx *DB)
Adds DISTINCT to the query. If column names are provided they are also passed to Select.
// SELECT DISTINCT name FROM users
db.Distinct("name").Find(&results)

// SELECT DISTINCT name, age FROM users
db.Distinct("name", "age").Find(&results)

Select

func (db *DB) Select(query interface{}, args ...interface{}) (tx *DB)
Specifies which columns to include in the query. Accepts a string (with optional ? or @name placeholders), a slice of strings, or a raw SQL expression.
// Named columns
db.Select("name", "age").Find(&users)

// Column slice
db.Select([]string{"name", "age"}).Find(&users)

// Expression with placeholder
db.Select("COALESCE(name, ?) AS name", "unknown").Find(&users)

Omit

func (db *DB) Omit(columns ...string) (tx *DB)
Excludes specific columns from create, update, and query operations. Also used to skip association saves when passed an association field name.
// Skip the Email column when creating
db.Omit("Email").Create(&user)

// Skip the Languages association when saving
db.Omit("Languages.*").Create(&user)

MapColumns

func (db *DB) MapColumns(m map[string]string) (tx *DB)
Provides a column name mapping applied to query results before scanning into the destination. Keys are result column names; values are the struct field names or target column names.
db.MapColumns(map[string]string{
    "full_name": "Name",
    "user_age":  "Age",
}).Find(&users)

Where

func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB)
Adds AND conditions to the query. Multiple calls to Where are combined with AND. Accepts a SQL string with ? or @name placeholders, a struct, or a map.
// SQL string
db.Where("name = ?", "jinzhu").First(&user)

// Struct (zero values are ignored)
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)

// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)

// Chained AND
db.Where("name = ?", "jinzhu").Where("age <> ?", 20).First(&user)
Use gorm.Expr inside Where to pass raw SQL expressions as values: db.Where("price > ?", gorm.Expr("original_price * 0.8"))

Not

func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB)
Adds a NOT condition. Accepts the same argument formats as Where.
// NOT name = 'jinzhu'
db.Not("name = ?", "jinzhu").First(&user)

// NOT IN
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)

Or

func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB)
Adds an OR condition chained to the preceding WHERE conditions.
// WHERE name = 'jinzhu' OR name = 'john'
db.Where("name = ?", "jinzhu").Or("name = ?", "john").First(&user)

// OR with struct
db.Where("name = 'jinzhu'").Or(User{Name: "john", Age: 20}).Find(&users)

Joins

func (db *DB) Joins(query string, args ...interface{}) (tx *DB)
Adds a LEFT JOIN clause. Can reference a named association or a raw SQL JOIN expression. When a *DB is passed as the sole extra argument, it is used as a scoped association join.
// Association join (preloads the joined fields)
db.Joins("Account").Find(&users)

// Raw SQL join
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?",
    "[email protected]").Find(&users)

// Scoped association join
db.Joins("Account",
    db.Select("id").Where("user_id = users.id AND name = ?", "someName").Model(&Account{}),
).Find(&users)

InnerJoins

func (db *DB) InnerJoins(query string, args ...interface{}) (tx *DB)
Like Joins but produces an INNER JOIN instead of LEFT JOIN.
db.InnerJoins("Account").Find(&users)

Group

func (db *DB) Group(name string) (tx *DB)
Adds a GROUP BY clause.
// SELECT name, sum(age) AS total FROM users GROUP BY name
db.Model(&User{}).Select("name, sum(age) as total").Group("name").Find(&results)

Having

func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB)
Adds a HAVING clause after GROUP BY. Accepts the same argument formats as Where.
// SELECT name, sum(age) AS total FROM users GROUP BY name HAVING name = 'jinzhu'
db.Model(&User{}).
    Select("name, sum(age) as total").
    Group("name").
    Having("name = ?", "jinzhu").
    Find(&result)

Order

func (db *DB) Order(value interface{}) (tx *DB)
Specifies the ORDER BY direction. Accepts a string, a clause.OrderByColumn, or a clause.OrderBy for multiple columns.
// String
db.Order("name DESC").Find(&users)

// Struct with direction
db.Order(clause.OrderByColumn{
    Column: clause.Column{Name: "name"},
    Desc:   true,
}).Find(&users)

// Multiple columns
db.Order(clause.OrderBy{
    Columns: []clause.OrderByColumn{
        {Column: clause.Column{Name: "name"}, Desc: true},
        {Column: clause.Column{Name: "age"}, Desc: false},
    },
}).Find(&users)

Limit

func (db *DB) Limit(limit int) (tx *DB)
Limits the number of records returned. Pass -1 to cancel a previously set limit.
// Retrieve at most 3 records
db.Limit(3).Find(&users)

// Cancel a previously set limit
db.Limit(3).Find(&users1).Limit(-1).Find(&users2)

Offset

func (db *DB) Offset(offset int) (tx *DB)
Skips the specified number of records before returning results. Pass -1 to cancel a previously set offset.
// Skip first 5 records
db.Offset(5).Find(&users)

// Cancel offset
db.Offset(5).Offset(-1).Find(&users)

Scopes

func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB)
Registers one or more reusable query functions. The functions are applied lazily when a finisher method is called, each receiving and returning a *DB.
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
    return db.Where("amount > ?", 1000)
}

func OrderStatus(status []string) func(*gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Where("status IN (?)", status)
    }
}

db.Scopes(
    AmountGreaterThan1000,
    OrderStatus([]string{"paid", "shipped"}),
).Find(&orders)

Preload

func (db *DB) Preload(query string, args ...interface{}) (tx *DB)
Eagerly loads an association in a separate SQL query after the primary query. Multiple Preload calls can be chained to load multiple associations. Use clause.Associations to preload all.
// Preload all orders
db.Preload("Orders").Find(&users)

// Preload with condition
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)

// Nested preload
db.Preload("Orders.OrderItems").Find(&users)

// Preload all associations
db.Preload(clause.Associations).Find(&users)

Attrs

func (db *DB) Attrs(attrs ...interface{}) (tx *DB)
Sets attributes to be assigned to the record only when it is not found (used with FirstOrInit and FirstOrCreate). If the record exists, Attrs values are ignored.
// Email is only set when the record is not found
db.Where(User{Name: "non_existing"}).
    Attrs(User{Email: "[email protected]"}).
    FirstOrInit(&user)

Assign

func (db *DB) Assign(attrs ...interface{}) (tx *DB)
Sets attributes to be assigned to the record regardless of whether it was found or not (used with FirstOrInit and FirstOrCreate). With FirstOrCreate, existing records are updated.
// Email is always set, even if the record exists
db.Where(User{Name: "jinzhu"}).
    Assign(User{Email: "[email protected]"}).
    FirstOrInit(&user)

Unscoped

func (db *DB) Unscoped() (tx *DB)
Disables soft-delete filtering for the query. Records with a non-null DeletedAt (or equivalent) are included in results and can be hard-deleted.
// Query includes soft-deleted records
db.Unscoped().Find(&users)

// Permanently delete a soft-deleted record
db.Unscoped().Delete(&user)

Raw

func (db *DB) Raw(sql string, values ...interface{}) (tx *DB)
Sets a raw SQL string as the statement. Used in combination with Scan or Rows to execute arbitrary queries. Supports both ? positional and @name named placeholders.
// Positional placeholder
db.Raw("SELECT id, name FROM users WHERE name = ?", "jinzhu").Scan(&result)

// Named placeholder
db.Raw("SELECT * FROM users WHERE name = @name", sql.Named("name", "jinzhu")).Scan(&users)
Raw sets the SQL string directly on the statement. Call a finisher such as Scan, Rows, or Row to execute it — do not follow Raw with Find, First, etc.

Build docs developers (and LLMs) love