Skip to main content
Event hooks allow you to execute custom logic at specific points in PocketBase’s lifecycle. You can use them to validate data, trigger side effects, send notifications, and more.

Hook types

PocketBase provides several categories of event hooks:
  • Application hooks: App lifecycle events (bootstrap, serve, terminate)
  • Model hooks: Generic model operations (create, update, delete, validate)
  • Record hooks: Record-specific operations
  • Collection hooks: Collection management events
  • Auth hooks: Authentication and authorization events
  • Request hooks: API request/response events
  • Mailer hooks: Email sending events
  • Settings hooks: Application settings events

Hook execution flow

Each hook follows this pattern: You can:
  • Prevent the default behavior by returning an error
  • Modify the event data before it’s processed
  • Execute side effects (logging, notifications, etc.)
  • Chain multiple handlers with priorities

Application hooks

OnBootstrap

Triggered when the application initializes.
app.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
    log.Println("App bootstrapping...")
    // Initialize custom services
    return e.Next()
})

OnServe

Triggered when the HTTP server is about to start. Use this to register custom routes.
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
    // Add custom routes
    e.Router.GET("/api/health", func(re *core.RequestEvent) error {
        return re.JSON(200, map[string]string{"status": "ok"})
    })
    
    return e.Next()
})

OnTerminate

Triggered when the application is shutting down.
app.OnTerminate().BindFunc(func(e *core.TerminateEvent) error {
    log.Println("App terminating...")
    // Cleanup resources
    return e.Next()
})

Model hooks

Model hooks work with any model type (records, collections, settings, etc.).

OnModelCreate

Triggered before a model is created.
app.OnModelCreate().BindFunc(func(e *core.ModelEvent) error {
    log.Printf("Creating model: %s\n", e.Model.TableName())
    return e.Next()
})

OnModelUpdate

Triggered before a model is updated.
app.OnModelUpdate().BindFunc(func(e *core.ModelEvent) error {
    log.Printf("Updating model: %s\n", e.Model.TableName())
    return e.Next()
})

OnModelDelete

Triggered before a model is deleted.
app.OnModelDelete().BindFunc(func(e *core.ModelEvent) error {
    log.Printf("Deleting model: %s\n", e.Model.TableName())
    return e.Next()
})

Record hooks

Record hooks are specific to data records and support collection filtering.

OnRecordCreate

Triggered before a record is created.
// For all collections
app.OnRecordCreate().BindFunc(func(e *core.RecordEvent) error {
    log.Printf("Creating record in %s\n", e.Record.Collection().Name)
    return e.Next()
})

// For specific collection
app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
    // Validate post data
    title := e.Record.GetString("title")
    if len(title) < 5 {
        return errors.New("title too short")
    }
    return e.Next()
})

OnRecordUpdate

Triggered before a record is updated.
app.OnRecordUpdate("posts").BindFunc(func(e *core.RecordEvent) error {
    // Track what changed
    original := e.Record.OriginalCopy()
    if original.GetString("status") != e.Record.GetString("status") {
        log.Println("Status changed")
    }
    return e.Next()
})

OnRecordDelete

Triggered before a record is deleted.
app.OnRecordDelete("posts").BindFunc(func(e *core.RecordEvent) error {
    log.Printf("Deleting post: %s\n", e.Record.Id)
    // Clean up related data
    return e.Next()
})

After hooks

All record hooks also have “after” variants that run after the operation completes:
  • OnRecordAfterCreateSuccess / onRecordAfterCreateSuccess
  • OnRecordAfterUpdateSuccess / onRecordAfterUpdateSuccess
  • OnRecordAfterDeleteSuccess / onRecordAfterDeleteSuccess
app.OnRecordAfterCreateSuccess("posts").BindFunc(func(e *core.RecordEvent) error {
    // Send notification after successful creation
    log.Printf("Post created successfully: %s\n", e.Record.Id)
    return e.Next()
})

Auth hooks

Hooks for authentication and authorization events.

OnRecordAuthRequest

Triggered on any successful authentication.
app.OnRecordAuthRequest().BindFunc(func(e *core.RecordAuthRequestEvent) error {
    log.Printf("User %s authenticated via %s\n", 
        e.Record.Id, e.AuthMethod)
    return e.Next()
})

OnRecordAuthWithPasswordRequest

Triggered on password authentication.
app.OnRecordAuthWithPasswordRequest().BindFunc(
    func(e *core.RecordAuthWithPasswordRequestEvent) error {
        // Log authentication attempts
        log.Printf("Password auth attempt: %s\n", e.Identity)
        return e.Next()
    },
)

OnRecordAuthWithOAuth2Request

Triggered on OAuth2 authentication.
app.OnRecordAuthWithOAuth2Request().BindFunc(
    func(e *core.RecordAuthWithOAuth2RequestEvent) error {
        log.Printf("OAuth2 auth: %s\n", e.ProviderName)
        
        // Customize user data on first auth
        if e.IsNewRecord {
            e.Record.Set("verified", true)
        }
        
        return e.Next()
    },
)

Collection hooks

Hooks for collection management.

OnCollectionCreate

app.OnCollectionCreate().BindFunc(func(e *core.CollectionEvent) error {
    log.Printf("Collection created: %s\n", e.Collection.Name)
    return e.Next()
})

OnCollectionUpdate

app.OnCollectionUpdate().BindFunc(func(e *core.CollectionEvent) error {
    log.Printf("Collection updated: %s\n", e.Collection.Name)
    return e.Next()
})

Request hooks

Hooks for API requests.

OnRecordsListRequest

app.OnRecordsListRequest("posts").BindFunc(
    func(e *core.RecordsListRequestEvent) error {
        // Modify query parameters
        log.Printf("Listing posts, found %d\n", e.Result.TotalItems)
        return e.Next()
    },
)

OnRecordViewRequest

app.OnRecordViewRequest("posts").BindFunc(
    func(e *core.RecordRequestEvent) error {
        // Track views
        views := e.Record.GetInt("views")
        e.Record.Set("views", views+1)
        app.Save(e.Record)
        return e.Next()
    },
)

Mailer hooks

OnMailerSend

Triggered before sending any email.
app.OnMailerSend().BindFunc(func(e *core.MailerEvent) error {
    log.Printf("Sending email to: %v\n", e.Message.To)
    // Modify email content or prevent sending
    return e.Next()
})

OnMailerRecordAuthAlertSend

Triggered when sending authentication alert emails.
app.OnMailerRecordAuthAlertSend().BindFunc(
    func(e *core.MailerRecordEvent) error {
        // Customize auth alert emails
        e.Message.Subject = "Security Alert: New Login"
        return e.Next()
    },
)

Settings hooks

OnSettingsListRequest

app.OnSettingsListRequest().BindFunc(
    func(e *core.SettingsListRequestEvent) error {
        // Modify settings before returning
        return e.Next()
    },
)

OnSettingsUpdateRequest

app.OnSettingsUpdateRequest().BindFunc(
    func(e *core.SettingsUpdateRequestEvent) error {
        // Validate settings changes
        return e.Next()
    },
)

Hook priorities

You can control the execution order of hooks using priorities:
app.OnRecordCreate("posts").Bind(&hook.Handler[*core.RecordEvent]{
    Id: "validate-title",
    Priority: 100, // Higher runs first
    Func: func(e *core.RecordEvent) error {
        // Validation logic
        return e.Next()
    },
})

app.OnRecordCreate("posts").Bind(&hook.Handler[*core.RecordEvent]{
    Id: "log-creation",
    Priority: 50, // Runs after validation
    Func: func(e *core.RecordEvent) error {
        log.Println("Post validated and ready to create")
        return e.Next()
    },
})

Stopping execution

Return an error to prevent the operation from completing:
app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
    if e.Record.GetString("status") == "spam" {
        return errors.New("spam content not allowed")
    }
    return e.Next()
})

Next steps

Custom routes

Learn how to add custom API endpoints

JavaScript hooks

More JavaScript hook examples