Save — update all fields
Save writes every field back to the database when the primary key is non-zero. Zero-value fields are included.
var user User
db.First(&user, 1)
user.Name = "Jinzhu Updated"
user.Age = 0 // zero value is written
db.Save(&user)
// UPDATE users SET name="Jinzhu Updated", age=0, updated_at=... WHERE id=1;
Save performs a full-record UPDATE. Every field, including zero-value fields, is written. Use Update or Updates when you only want to change specific columns.
Update — single column
Use Update with Model to update one column. The Model call sets the model context and, if the struct has a non-zero primary key, scopes the UPDATE to that record.
// Update a column on a specific record (primary key from the struct)
db.Model(&user).Update("name", "Jinzhu")
// UPDATE users SET name="Jinzhu", updated_at=... WHERE id=<user.ID>;
// Update with a condition
db.Model(&User{}).Where("active = ?", true).Update("name", "Jinzhu")
// UPDATE users SET name="Jinzhu", updated_at=... WHERE active=true;
// SQL expression
db.Model(&user).Update("age", gorm.Expr("age * ? + ?", 2, 100))
// UPDATE users SET age=age*2+100 WHERE id=<user.ID>;
Updates — multiple columns
Updates accepts a struct or a map.
Struct (non-zero fields only)
When you pass a struct, GORM only updates fields with non-zero values.
// Only Name and Age are updated; zero-value fields are skipped
db.Model(&user).Updates(User{Name: "Jinzhu", Age: 18})
// UPDATE users SET name="Jinzhu", age=18, updated_at=... WHERE id=<user.ID>;
// Age is zero → only Name is updated
db.Model(&user).Updates(User{Name: "Jinzhu", Age: 0})
// UPDATE users SET name="Jinzhu", updated_at=... WHERE id=<user.ID>;
To update a field to its zero value using a struct, use Select to explicitly include it, or switch to a map.
Map (all keys updated)
Every key in the map is written, including zero values.
db.Model(&user).Updates(map[string]interface{}{
"name": "Jinzhu",
"age": 0, // zero value is written
"active": false, // zero bool is written
})
// UPDATE users SET name="Jinzhu", age=0, active=false, updated_at=... WHERE id=<user.ID>;
Selecting fields for update
Use Select to control exactly which fields are written, regardless of whether you pass a struct or a map.
// Update only Name, even though Address and Role are set in the map
db.Model(&user).
Select("Name").
Updates(map[string]interface{}{"Name": "New Name", "Age": 100})
// UPDATE users SET name="New Name" WHERE id=<user.ID>;
// Force update ALL fields including zero values by selecting "*"
db.Model(&user).
Select("*").
Updates(User{Name: "Jinzhu", Age: 0, Role: "admin"})
// UPDATE users SET name="Jinzhu", age=0, role="admin", updated_at=... WHERE id=<user.ID>;
// Select all except a specific field
db.Model(&user).
Select("*").
Omit("Role").
Updates(User{Name: "Jinzhu", Age: 20, Role: "admin"})
// UPDATE users SET name="Jinzhu", age=20, updated_at=... WHERE id=<user.ID>;
Omitting fields on update
Use Omit to exclude specific columns from the UPDATE.
db.Model(&user).
Omit("Name").
Updates(map[string]interface{}{"Name": "Jinzhu", "Age": 20})
// UPDATE users SET age=20, updated_at=... WHERE id=<user.ID>;
SQL expressions in updates
Use gorm.Expr to embed raw SQL expressions in an update value.
// Increment a counter
db.Model(&product).
Update("price", gorm.Expr("price * ? + ?", 1.1, 10))
// UPDATE products SET price=price*1.1+10 WHERE id=<product.ID>;
// Map with expressions
db.Model(&product).Updates(map[string]interface{}{
"price": gorm.Expr("price * ?", 1.1),
"quantity": gorm.Expr("quantity - ?", 1),
})
UpdateColumn and UpdateColumns — skip hooks
UpdateColumn and UpdateColumns behave like Update and Updates respectively, but they skip all GORM callbacks (hooks) and do not auto-update the UpdatedAt timestamp.
// Single column, no hooks, no UpdatedAt
db.Model(&user).UpdateColumn("name", "Jinzhu")
// UPDATE users SET name="Jinzhu" WHERE id=<user.ID>;
// Multiple columns via struct
db.Model(&user).UpdateColumns(User{Name: "Jinzhu", Age: 18})
// UPDATE users SET name="Jinzhu", age=18 WHERE id=<user.ID>;
// Multiple columns via map
db.Model(&user).UpdateColumns(map[string]interface{}{
"name": "Jinzhu",
"age": 18,
})
Because UpdateColumn/UpdateColumns skip all hooks, the BeforeUpdate, AfterUpdate, and association update callbacks are not executed.
Batch updates
Omit the primary key from Model and add a Where condition to update multiple rows:
// Update all users where active = false
db.Model(&User{}).
Where("active = ?", false).
Updates(map[string]interface{}{"active": true, "role": "member"})
// UPDATE users SET active=true, role="member", updated_at=... WHERE active=false;
// Struct-based batch update (non-zero fields only)
db.Model(User{}).
Where("role = ?", "guest").
Updates(User{Role: "member"})
Check RowsAffected to see how many rows were changed:
result := db.Model(&User{}).Where("age < ?", 18).Updates(User{Role: "minor"})
fmt.Println(result.RowsAffected) // number of updated rows
GORM prevents batch updates without a WHERE condition and returns gorm.ErrMissingWhereClause. To intentionally update all rows, use db.Where("1 = 1").Updates(...) or the AllowGlobalUpdate session option.
Error handling
result := db.Model(&user).Update("name", "Jinzhu")
if result.Error != nil {
// handle error
}