Model Hooks
Hooks run at specific points in a model's lifecycle. Use them to hash passwords, validate data, send notifications, update timestamps, or clean up related records.
Available Hooks
| Hook | When | Common Uses |
|---|---|---|
| BeforeCreate | Before INSERT | Hash passwords, set defaults, generate UUIDs |
| AfterCreate | After INSERT | Send welcome email, create related records |
| BeforeUpdate | Before UPDATE | Validate changes, re-hash if password changed |
| AfterUpdate | After UPDATE | Invalidate cache, log changes |
| BeforeSave | Before INSERT or UPDATE | Slug generation, sanitize HTML |
| AfterSave | After INSERT or UPDATE | Sync search index, emit events |
| BeforeDelete | Before DELETE | Check constraints, archive data |
| AfterDelete | After DELETE | Clean up files, remove cached data |
RegisterHooks
Use database.RegisterHooks to attach callbacks to a table. The Hooks struct lets you set any combination:
database.RegisterHooks(database.Get(), "users", database.Hooks{
BeforeCreate: func(db *gorm.DB) {
if u, ok := db.Statement.Dest.(*User); ok && u.Password != "" {
hashed, _ := hash.Make(u.Password)
u.Password = hashed
}
},
AfterCreate: func(db *gorm.DB) {
if u, ok := db.Statement.Dest.(*User); ok {
// Send welcome email
notification.Send(&WelcomeNotification{User: u})
}
},
BeforeSave: func(db *gorm.DB) {
if p, ok := db.Statement.Dest.(*Post); ok {
// Auto-generate slug
p.Slug = slugify(p.Title)
}
},
AfterDelete: func(db *gorm.DB) {
if p, ok := db.Statement.Dest.(*Post); ok {
// Clean up uploaded images
os.Remove(p.ImagePath)
}
},
})
Hooks Struct
type Hooks struct {
BeforeCreate func(db *gorm.DB)
AfterCreate func(db *gorm.DB)
BeforeUpdate func(db *gorm.DB)
AfterUpdate func(db *gorm.DB)
BeforeSave func(db *gorm.DB)
AfterSave func(db *gorm.DB)
BeforeDelete func(db *gorm.DB)
AfterDelete func(db *gorm.DB)
}
// Only set the hooks you need — nil hooks are skipped
Accessing the Model
Inside hooks, access the model being saved/deleted via db.Statement.Dest:
BeforeUpdate: func(db *gorm.DB) {
if u, ok := db.Statement.Dest.(*User); ok {
// u is the User being updated
u.UpdatedBy = getCurrentAdmin()
}
}
Cache Invalidation Hook
Combine with cache invalidation:
database.RegisterHooks(db, "posts", database.Hooks{
AfterSave: func(db *gorm.DB) {
cache.Forget(ctx, "posts:list")
cache.Forget(ctx, fmt.Sprintf("posts:%d", post.ID))
},
AfterDelete: func(db *gorm.DB) {
cache.Forget(ctx, "posts:list")
},
})
GORM Callbacks (Alternative)
For more control, use GORM's callback API directly:
db.Callback().Create().Before("gorm:before_create").Register("hash_password", func(db *gorm.DB) {
// ...
})