> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/pocketbase/pocketbase/llms.txt
> Use this file to discover all available pages before exploring further.

# Event hooks

> Complete reference for PocketBase event hooks in Go and JavaScript

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:

```mermaid theme={null}
graph LR
    A[Before Event] --> B[Handler 1]
    B --> C[Handler 2]
    C --> D[Handler N]
    D --> E[Core Logic]
    E --> F[After Handlers]
```

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.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
        log.Println("App bootstrapping...")
        // Initialize custom services
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onBootstrap((e) => {
        console.log("App bootstrapping...")
        // Initialize custom services
    })
    ```
  </Tab>
</Tabs>

### OnServe

Triggered when the HTTP server is about to start. Use this to register custom routes.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Note: Use routerAdd() instead in JavaScript
    routerAdd("GET", "/api/health", (e) => {
        return e.json(200, {status: "ok"})
    })
    ```
  </Tab>
</Tabs>

### OnTerminate

Triggered when the application is shutting down.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnTerminate().BindFunc(func(e *core.TerminateEvent) error {
        log.Println("App terminating...")
        // Cleanup resources
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onTerminate((e) => {
        console.log("App terminating...")
        // Cleanup resources
    })
    ```
  </Tab>
</Tabs>

## Model hooks

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

### OnModelCreate

Triggered before a model is created.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnModelCreate().BindFunc(func(e *core.ModelEvent) error {
        log.Printf("Creating model: %s\n", e.Model.TableName())
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onModelCreate((e) => {
        console.log("Creating model:", e.model.tableName())
    })
    ```
  </Tab>
</Tabs>

### OnModelUpdate

Triggered before a model is updated.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnModelUpdate().BindFunc(func(e *core.ModelEvent) error {
        log.Printf("Updating model: %s\n", e.Model.TableName())
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onModelUpdate((e) => {
        console.log("Updating model:", e.model.tableName())
    })
    ```
  </Tab>
</Tabs>

### OnModelDelete

Triggered before a model is deleted.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnModelDelete().BindFunc(func(e *core.ModelEvent) error {
        log.Printf("Deleting model: %s\n", e.Model.TableName())
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onModelDelete((e) => {
        console.log("Deleting model:", e.model.tableName())
    })
    ```
  </Tab>
</Tabs>

## Record hooks

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

### OnRecordCreate

Triggered before a record is created.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    // 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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // For all collections
    onRecordCreate((e) => {
        console.log("Creating record in", e.record.collection().name)
    })

    // For specific collection
    onRecordCreate((e) => {
        const title = e.record.get("title")
        if (title.length < 5) {
            throw new BadRequestError("Title too short")
        }
    }, "posts")
    ```
  </Tab>
</Tabs>

### OnRecordUpdate

Triggered before a record is updated.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordUpdate((e) => {
        const original = e.record.originalCopy()
        if (original.get("status") !== e.record.get("status")) {
            console.log("Status changed")
        }
    }, "posts")
    ```
  </Tab>
</Tabs>

### OnRecordDelete

Triggered before a record is deleted.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordDelete((e) => {
        console.log("Deleting post:", e.record.id)
        // Clean up related data
    }, "posts")
    ```
  </Tab>
</Tabs>

### After hooks

All record hooks also have "after" variants that run after the operation completes:

* `OnRecordAfterCreateSuccess` / `onRecordAfterCreateSuccess`
* `OnRecordAfterUpdateSuccess` / `onRecordAfterUpdateSuccess`
* `OnRecordAfterDeleteSuccess` / `onRecordAfterDeleteSuccess`

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordAfterCreateSuccess((e) => {
        // Send notification after successful creation
        console.log("Post created successfully:", e.record.id)
    }, "posts")
    ```
  </Tab>
</Tabs>

## Auth hooks

Hooks for authentication and authorization events.

### OnRecordAuthRequest

Triggered on any successful authentication.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnRecordAuthRequest().BindFunc(func(e *core.RecordAuthRequestEvent) error {
        log.Printf("User %s authenticated via %s\n", 
            e.Record.Id, e.AuthMethod)
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordAuthRequest((e) => {
        console.log(`User ${e.record.id} authenticated via ${e.authMethod}`)
    })
    ```
  </Tab>
</Tabs>

### OnRecordAuthWithPasswordRequest

Triggered on password authentication.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnRecordAuthWithPasswordRequest().BindFunc(
        func(e *core.RecordAuthWithPasswordRequestEvent) error {
            // Log authentication attempts
            log.Printf("Password auth attempt: %s\n", e.Identity)
            return e.Next()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordAuthWithPasswordRequest((e) => {
        console.log("Password auth attempt:", e.identity)
    })
    ```
  </Tab>
</Tabs>

### OnRecordAuthWithOAuth2Request

Triggered on OAuth2 authentication.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordAuthWithOAuth2Request((e) => {
        console.log("OAuth2 auth:", e.providerName)
        
        if (e.isNewRecord) {
            e.record.set("verified", true)
        }
    })
    ```
  </Tab>
</Tabs>

## Collection hooks

Hooks for collection management.

### OnCollectionCreate

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnCollectionCreate().BindFunc(func(e *core.CollectionEvent) error {
        log.Printf("Collection created: %s\n", e.Collection.Name)
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onCollectionCreate((e) => {
        console.log("Collection created:", e.collection.name)
    })
    ```
  </Tab>
</Tabs>

### OnCollectionUpdate

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnCollectionUpdate().BindFunc(func(e *core.CollectionEvent) error {
        log.Printf("Collection updated: %s\n", e.Collection.Name)
        return e.Next()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onCollectionUpdate((e) => {
        console.log("Collection updated:", e.collection.name)
    })
    ```
  </Tab>
</Tabs>

## Request hooks

Hooks for API requests.

### OnRecordsListRequest

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordsListRequest((e) => {
        console.log("Listing posts, found", e.result.totalItems)
    }, "posts")
    ```
  </Tab>
</Tabs>

### OnRecordViewRequest

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordViewRequest((e) => {
        const views = e.record.get("views")
        e.record.set("views", views + 1)
        $app.save(e.record)
    }, "posts")
    ```
  </Tab>
</Tabs>

## Mailer hooks

### OnMailerSend

Triggered before sending any email.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onMailerSend((e) => {
        console.log("Sending email to:", e.message.to)
    })
    ```
  </Tab>
</Tabs>

### OnMailerRecordAuthAlertSend

Triggered when sending authentication alert emails.

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnMailerRecordAuthAlertSend().BindFunc(
        func(e *core.MailerRecordEvent) error {
            // Customize auth alert emails
            e.Message.Subject = "Security Alert: New Login"
            return e.Next()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onMailerRecordAuthAlertSend((e) => {
        e.message.subject = "Security Alert: New Login"
    })
    ```
  </Tab>
</Tabs>

## Settings hooks

### OnSettingsListRequest

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnSettingsListRequest().BindFunc(
        func(e *core.SettingsListRequestEvent) error {
            // Modify settings before returning
            return e.Next()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onSettingsListRequest((e) => {
        // Modify settings before returning
    })
    ```
  </Tab>
</Tabs>

### OnSettingsUpdateRequest

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    app.OnSettingsUpdateRequest().BindFunc(
        func(e *core.SettingsUpdateRequestEvent) error {
            // Validate settings changes
            return e.Next()
        },
    )
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onSettingsUpdateRequest((e) => {
        // Validate settings changes
    })
    ```
  </Tab>
</Tabs>

## Hook priorities

You can control the execution order of hooks using priorities:

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
        },
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // JavaScript hooks don't support explicit priorities
    // They run in the order they're defined in your files
    ```
  </Tab>
</Tabs>

## Stopping execution

Return an error to prevent the operation from completing:

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    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()
    })
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    onRecordCreate((e) => {
        if (e.record.get("status") === "spam") {
            throw new BadRequestError("Spam content not allowed")
        }
    }, "posts")
    ```
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Custom routes" icon="route" href="/extending/custom-routes">
    Learn how to add custom API endpoints
  </Card>

  <Card title="JavaScript hooks" icon="js" href="/extending/javascript-hooks">
    More JavaScript hook examples
  </Card>
</CardGroup>
