Skip to main content
Finisher methods execute the accumulated statement, triggering the relevant GORM callback chain (create, query, update, delete, or raw). They always return a *DB (or a Go value for Row, Rows, ScanRows, Connection, and Transaction), and errors are stored on db.Error.
result := db.Where("age > ?", 18).Find(&users)
if result.Error != nil {
    // handle error
}
fmt.Println(result.RowsAffected)

Create

func (db *DB) Create(value interface{}) (tx *DB)
Inserts value into the database and populates the primary key field on the struct. If Config.CreateBatchSize is set and value is a slice, delegates to CreateInBatches automatically.
user := User{Name: "jinzhu", Age: 18}
result := db.Create(&user)
// user.ID is now populated
// result.Error contains any error
// result.RowsAffected == 1
Always pass a pointer to Create. Passing a value (non-pointer) will not update the primary key field.

CreateInBatches

func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB)
Inserts a slice of records in chunks of batchSize. Each chunk is wrapped in a transaction (unless SkipDefaultTransaction is set or the whole slice fits in one batch).
var users = []User{{Name: "user1"}, {Name: "user2"}, {Name: "user3"}}
db.CreateInBatches(&users, 100)

Save

func (db *DB) Save(value interface{}) (tx *DB)
Updates all fields of a record if it has a non-zero primary key, otherwise inserts it. Unlike Updates, Save includes zero-value fields. For slices, performs an upsert with ON CONFLICT UpdateAll.
// Insert (ID is zero)
db.Save(&User{Name: "jinzhu", Age: 18})

// Update all fields (ID is non-zero)
db.Save(&User{ID: 1, Name: "jinzhu", Age: 100})
Save with a struct that has a non-zero primary key will update all columns, including zero-value ones. Use Updates to update only specific fields.

First

func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB)
Retrieves the first record ordered by the primary key ascending. Sets ErrRecordNotFound on db.Error if no record matches.
// Primary key lookup
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10 ORDER BY id LIMIT 1

// With condition
db.First(&user, "name = ?", "jinzhu")

Take

func (db *DB) Take(dest interface{}, conds ...interface{}) (tx *DB)
Retrieves one record with no specified ordering (database-engine dependent). Sets ErrRecordNotFound if no match.
db.Take(&user)
// SELECT * FROM users LIMIT 1

db.Take(&user, "name = ?", "jinzhu")
Use First when you need deterministic ordering by primary key. Use Take when ordering does not matter and you want to avoid the ORDER BY cost.

Last

func (db *DB) Last(dest interface{}, conds ...interface{}) (tx *DB)
Retrieves the last record ordered by the primary key descending. Sets ErrRecordNotFound if no match.
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1

Find

func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB)
Retrieves all records matching the conditions. Scans into a slice or a single struct. Does not return ErrRecordNotFound when the result set is empty.
// All users
db.Find(&users)

// With inline condition
db.Find(&users, "name <> ? AND age > ?", "jinzhu", 18)

// Into a map slice
var results []map[string]interface{}
db.Model(&User{}).Find(&results)

FindInBatches

func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB
Queries records in successive batches of batchSize, calling fc for each batch. Results are ordered by primary key; each subsequent batch starts after the last primary key of the previous batch. Stops when fc returns an error or fewer than batchSize records are returned.
db.Where("age > ?", 18).FindInBatches(&users, 100, func(tx *gorm.DB, batch int) error {
    for i := range users {
        // process users[i]
    }
    return nil // return an error to stop
})

FirstOrInit

func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB)
Finds the first record matching the conditions. If not found, initialises dest with the condition values plus any Attrs values (but does not insert into the database). Assign values are always applied regardless.
// Initialise if not found — does not create
db.FirstOrInit(&user, User{Name: "non_existing"})

db.Where(User{Name: "non_existing"}).
    Attrs(User{Email: "[email protected]"}).
    FirstOrInit(&user)
// user.Email == "[email protected]" only if the user was not found

FirstOrCreate

func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB)
Finds the first record matching the conditions, or creates it if it does not exist. Assign values are always applied and will trigger an Updates call even if the record was found.
// Get or create
db.FirstOrCreate(&user, User{Name: "non_existing"})

// With Assign — updates record even if found
db.Where(User{Name: "jinzhu"}).
    Assign(User{Age: 20}).
    FirstOrCreate(&user)

Update

func (db *DB) Update(column string, value interface{}) (tx *DB)
Updates a single column. Runs through the update callbacks. Requires a model with a primary key or a Where clause.
// Update one column — requires Model or Where condition
db.Model(&user).Update("name", "hello")

// With raw SQL expression
db.Model(&product).Update("price", gorm.Expr("price * ? + ?", 0.9, 10))

Updates

func (db *DB) Updates(values interface{}) (tx *DB)
Updates multiple columns from a struct or map. When a struct is provided, only non-zero fields are updated. Runs through the update callbacks.
// Struct — only non-zero fields are updated
db.Model(&user).Updates(User{Name: "hello", Age: 18})

// Map — all keys are updated, including zero values
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 0})

UpdateColumn

func (db *DB) UpdateColumn(column string, value interface{}) (tx *DB)
Updates a single column without running hooks or updating the UpdatedAt timestamp.
db.Model(&user).UpdateColumn("name", "hello")

UpdateColumns

func (db *DB) UpdateColumns(values interface{}) (tx *DB)
Updates multiple columns without running hooks or updating the UpdatedAt timestamp. Accepts a struct or map.
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
db.Model(&user).UpdateColumns(map[string]interface{}{"name": "hello", "age": 0})

Delete

func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB)
Deletes records matching value and any optional conds. If the model has a DeletedAt field, performs a soft delete by setting the current timestamp. Use Unscoped().Delete for hard deletion.
// Delete by primary key in struct
db.Delete(&user)

// Delete with condition
db.Delete(&User{}, "name = ?", "jinzhu")

// Hard delete a soft-deleted record
db.Unscoped().Delete(&user)
Without a model primary key or a Where clause, GORM returns ErrMissingWhereClause (unless AllowGlobalUpdate is set) to prevent accidental table wipes.

Count

func (db *DB) Count(count *int64) (tx *DB)
Counts the records matching the current conditions. The result is stored in the *int64 pointed to by count.
var count int64
db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)

// DISTINCT count
db.Model(&User{}).Distinct("name").Count(&count)

Row

func (db *DB) Row() *sql.Row
Executes the query and returns a single *sql.Row for manual scanning. Use with Raw for arbitrary SQL.
row := db.Raw("SELECT name FROM users WHERE id = ?", 1).Row()
var name string
row.Scan(&name)

Rows

func (db *DB) Rows() (*sql.Rows, error)
Executes the query and returns a *sql.Rows cursor. You are responsible for closing the rows.
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Rows()
if err != nil {
    return err
}
defer rows.Close()

for rows.Next() {
    var user User
    db.ScanRows(rows, &user)
}

Scan

func (db *DB) Scan(dest interface{}) (tx *DB)
Scans the result of the current statement into dest. Similar to Find, but does not perform any model-based table name inference — useful after Raw or Table.
type Result struct { Name string; Age int }
var result Result
db.Raw("SELECT name, age FROM users WHERE id = ?", 1).Scan(&result)

var results []Result
db.Table("users").Select("name, age").Scan(&results)

Pluck

func (db *DB) Pluck(column string, dest interface{}) (tx *DB)
Queries a single column and scans the values into a slice.
var names []string
db.Model(&User{}).Pluck("name", &names)

var ages []int64
db.Model(&User{}).Pluck("age", &ages)

ScanRows

func (db *DB) ScanRows(rows *sql.Rows, dest interface{}) error
Scans a single row from an existing *sql.Rows cursor into dest. Typically used inside a Rows() loop.
rows, _ := db.Model(&User{}).Rows()
defer rows.Close()
for rows.Next() {
    var user User
    db.ScanRows(rows, &user)
    // process user
}

Connection

func (db *DB) Connection(fc func(tx *DB) error) (err error)
Acquires a dedicated connection from the pool, runs fc with that connection, and returns the connection to the pool when fc returns. Useful when you need a series of statements to execute on the same connection (e.g., for session-level settings).
db.Connection(func(tx *gorm.DB) error {
    tx.Exec("SET time_zone = '+08:00'")
    return tx.Find(&users).Error
})

Transaction

func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error)
Executes fc within a transaction. If fc returns an error, the transaction is rolled back; otherwise it is committed. Panics in fc also trigger a rollback. Supports nested transactions via savepoints (unless DisableNestedTransaction is set).
err := db.Transaction(func(tx *gorm.DB) error {
    if err := tx.Create(&user).Error; err != nil {
        return err // triggers rollback
    }
    if err := tx.Create(&product).Error; err != nil {
        return err
    }
    return nil // commit
})

Begin

func (db *DB) Begin(opts ...*sql.TxOptions) *DB
Starts a transaction manually and returns a new *DB operating within that transaction. You must call Commit or Rollback yourself. Prefer Transaction for automatic management.
tx := db.Begin()
if tx.Error != nil {
    return tx.Error
}

if err := tx.Create(&user).Error; err != nil {
    tx.Rollback()
    return err
}

tx.Commit()

Commit

func (db *DB) Commit() *DB
Commits the current transaction. Returns ErrInvalidTransaction if called outside a transaction.

Rollback

func (db *DB) Rollback() *DB
Rolls back the current transaction. Returns ErrInvalidTransaction if called outside a transaction.

SavePoint

func (db *DB) SavePoint(name string) *DB
Creates a named savepoint within the current transaction. Requires the dialector to implement SavePointerDialectorInterface. Returns ErrUnsupportedDriver if not supported.
tx := db.Begin()
tx.Create(&user)
tx.SavePoint("sp1")
tx.Create(&product) // if this fails:
tx.RollbackTo("sp1") // rolls back to before product creation
tx.Commit()

RollbackTo

func (db *DB) RollbackTo(name string) *DB
Rolls back the current transaction to a previously created savepoint. Requires the dialector to implement SavePointerDialectorInterface.

Exec

func (db *DB) Exec(sql string, values ...interface{}) (tx *DB)
Executes a raw SQL statement (DDL or DML) without scanning any results. Supports ? positional and @name named placeholders.
// DML
db.Exec("UPDATE orders SET shipped_at = ? WHERE id IN ?", time.Now(), []int{1, 2, 3})

// DDL
db.Exec("CREATE INDEX idx_name ON users(name)")

// Named placeholder
db.Exec("UPDATE users SET name = @name WHERE id = @id",
    sql.Named("name", "jinzhu"), sql.Named("id", 1))

Build docs developers (and LLMs) love