Use lifecycle hooks to run logic before or after GORM operations on your models.
Hooks are methods defined on your model struct that GORM calls automatically at specific points in the lifecycle of a database operation. You can use them to enforce business rules, update related data, or abort an operation by returning an error.
Define a hook as a pointer-receiver method on your model struct. The method must accept *gorm.DB and return error.
type User struct { gorm.Model Name string Email string Role string}func (u *User) BeforeCreate(tx *gorm.DB) error { if u.Role == "" { u.Role = "member" } return nil}func (u *User) AfterCreate(tx *gorm.DB) error { // Use tx for additional queries within the same transaction return tx.Model(u).Update("created_by", "system").Error}
The tx parameter inside a hook shares the same transaction as the triggering operation. Use it to perform additional queries that must succeed or fail together with the main operation.
// BeforeCreate called before inserting a recordfunc (u *User) BeforeCreate(tx *gorm.DB) error// AfterCreate called after inserting a recordfunc (u *User) AfterCreate(tx *gorm.DB) error// BeforeSave called before Create or Updatefunc (u *User) BeforeSave(tx *gorm.DB) error// AfterSave called after Create or Updatefunc (u *User) AfterSave(tx *gorm.DB) error// BeforeUpdate called before updating a recordfunc (u *User) BeforeUpdate(tx *gorm.DB) error// AfterUpdate called after updating a recordfunc (u *User) AfterUpdate(tx *gorm.DB) error// BeforeDelete called before deleting a recordfunc (u *User) BeforeDelete(tx *gorm.DB) error// AfterDelete called after deleting a recordfunc (u *User) AfterDelete(tx *gorm.DB) error// AfterFind called after a query (Find, First, Last, etc.)func (u *User) AfterFind(tx *gorm.DB) error
Beyond model methods, you can register callbacks globally on the db instance using the callback manager. This is useful for cross-cutting concerns like auditing or tracing.
// Register a callback that runs before every create operationdb.Callback().Create().Before("gorm:create").Register("audit:before_create", func(db *gorm.DB) { if db.Statement.Schema != nil { fmt.Printf("creating record in table: %s\n", db.Statement.Table) }})// Remove an existing callbackdb.Callback().Delete().Remove("gorm:delete")// Replace an existing callback with a custom implementationdb.Callback().Update().Replace("gorm:update", myCustomUpdateFunc)
Callback processors support Before, After, Match, Register, Remove, and Replace methods for fine-grained control over execution order.