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

HookWhenCommon Uses
BeforeCreateBefore INSERTHash passwords, set defaults, generate UUIDs
AfterCreateAfter INSERTSend welcome email, create related records
BeforeUpdateBefore UPDATEValidate changes, re-hash if password changed
AfterUpdateAfter UPDATEInvalidate cache, log changes
BeforeSaveBefore INSERT or UPDATESlug generation, sanitize HTML
AfterSaveAfter INSERT or UPDATESync search index, emit events
BeforeDeleteBefore DELETECheck constraints, archive data
AfterDeleteAfter DELETEClean 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) {
    // ...
})