| name | pb-extend |
| description | Extend PocketBase with custom hooks and routes in JS or Go. Use when user wants to add custom API routes, modify PocketBase behavior, or add server-side logic. |
| license | MIT |
| allowed-tools | Bash |
PocketBase Extending
Reference: https://pocketbase.io/docs/js-overview/ | https://pocketbase.io/docs/go-overview/
Extend PocketBase with custom hooks and routes in JS or Go.
JS Hooks (pb_hooks/)
Drop *.pb.js files in pb_hooks/:
router.api.post('/custom-route', async (e) => {
const body = e.request.body
return e.json({ result: 'ok' })
})
onRecordCreateRequest((e) => {
if (!e.record.get('email').endsWith('@company.com')) {
return e.badRequest('Use company email')
}
return e.next()
})
Rules:
- Always call
e.next() / e.Next() in hooks
- Variables outside handlers are undefined at runtime
- Use
require() for shared config (CJS only, no ESM)
Go Hooks (migrations/)
Versioned migrations in migrations/:
package migrations
import (
"github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/types"
)
func init() {
migrations.Register(func(app *pocketbase.App) error {
return nil
}, func(app *pocketbase.App) error {
return nil
})
}
Custom Routes
router.api.post('/api/myapp/send-email', async (e) => {
const data = await e.request.json()
await sendEmail(data.to, data.subject)
return e.json({ sent: true })
}, middleware.RequireAuth())
Key Hook Events
| Event | Purpose |
|---|
onRecordCreateRequest | Before record creation |
onRecordUpdateRequest | Before record update |
onRecordDeleteRequest | Before record deletion |
OnRecordEnrich | Shape response (incl. realtime) |
OnRecordRequest | HTTP-only response shaping |
OnBeforeServe | Modify router before serving |
Migrations
Auto-migrate: Collections changed via Admin UI auto-generate migrations in pb_migrations/
Manual JS migration:
migrate((up, down) => {
up((db) => {
db.createCollection('categories', { })
})
down((db) => {
db.dropCollection('categories')
})
})
Useful Settings
const settings = require('../pb_settings/config.js')
router.use(async (e) => {
const app = e.app
})