Go hooks and event lifecycle
Register PocketBase Go hooks for application, model, collection, mailer, and realtime events.
Use Go hooks to extend PocketBase at defined application, model, collection, mailer, filesystem, and realtime events. This reference shows the lifecycle boundaries that determine whether code runs before an operation, after its database statement, or after successful persistence.
Hook execution model
All hooks expose Bind, BindFunc, Trigger, Unbind, and UnbindAll. A handler has the shape func(e T) error; call e.Next() to continue the handler chain. Use e.App inside a handler because the event may belong to a transaction. Avoid global mutexes in handlers because hooks can run recursively.
The diagram shows the broad lifecycle. Model and collection events can also be triggered by scheduled jobs, console commands, or custom code, so do not assume every model hook has request context.
Application hooks
| Hook | Use it for | Lifecycle note |
|---|---|---|
OnBootstrap | Initialize resources after the application bootstrap begins | Call e.Next() before accessing initialized database resources. |
OnBootstrapClear | Release resources while bootstrap state is cleared | Access to the database after e.Next() is not available. |
OnServe | Add routes or middleware after the listener starts | Register server behavior before the blocking serve task. |
OnSettingsReload | React to a replaced settings state | Read the new settings after e.Next(). |
OnTerminate | Handle graceful termination | Abrupt termination may not wait for completion. |
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
e.Router.GET("/healthz", func(e *core.RequestEvent) error {
return e.String(200, "ok")
})
return e.Next()
})Record and collection hooks
Record model hooks such as OnRecordEnrich, OnRecordValidate, and OnRecordCreate can run from any application path and do not have request context. Use record *Request hooks when you need request headers, body, or auth state. OnRecordCreate runs before validation and the insert statement; OnRecordCreateExecute runs after validation and immediately before the insert. Successful hook execution does not guarantee the surrounding transaction committed. Use OnRecordAfterCreateSuccess or the matching success/error hooks for persistence outcomes.
Collection hooks expose the corresponding create, update, and delete stages, including OnCollectionDelete, OnCollectionDeleteExecute, OnCollectionAfterDeleteSuccess, and OnCollectionAfterDeleteError. Tagged hooks accept collection names, for example app.OnCollectionAfterDeleteSuccess("articles").
app.OnRecordEnrich("articles").BindFunc(func(e *core.RecordEnrichEvent) error {
if e.RequestInfo.Auth == nil {
e.Record.Hide("internalScore")
}
return e.Next()
})
app.OnCollectionAfterDeleteSuccess("articles").BindFunc(func(e *core.CollectionEvent) error {
e.App.Logger().Info("article collection changed")
return e.Next()
})Mailer hooks
OnMailerSend intercepts every message sent by App.NewMailClient(). Tagged mailer hooks cover password reset, verification, email change, OTP, and auth alert messages. Modify e.Message and continue with e.Next().
app.OnMailerSend().BindFunc(func(e *core.MailerEvent) error {
e.Message.Subject = "PocketBase notification"
return e.Next()
})Realtime hooks
Use OnRealtimeConnectRequest when the server establishes an SSE client, OnRealtimeSubscribeRequest when subscriptions change, and OnRealtimeMessageSend before an SSE message is delivered. Code after e.Next() in the connect hook runs after the client disconnects.
app.OnRealtimeSubscribeRequest().BindFunc(func(e *core.RealtimeSubscribeRequestEvent) error {
if len(e.Subscriptions) == 0 {
return e.BadRequestError("At least one subscription is required", nil)
}
return e.Next()
})Verify hook behavior
Bind a temporary handler with a distinctive log message, exercise the operation, and confirm the message appears at the expected lifecycle point. If a handler returns an error before e.Next(), the chain stops; if it returns the result of e.Next(), later handlers and the underlying operation can continue.
Next steps
Use Go records, queries, and database operations for the data operation inside a hook, or Go jobs and realtime messaging for background and custom message workflows.