PocketBase — API Surface#
API types#
REST/HTTP API, CLI (Cobra), Library (Go embedding API), Plugin/Extension system (hook-based + JavaScript JSVM)
REST/HTTP API#
Router#
- Router: Custom
tools/router — a thin wrapper around Go 1.22 stdlib net/http with {param} and {path...} pattern matching, extended via tools/hook for per-route middleware chains. - Route registration: Explicit functional binding in
apis/base.go:NewRouter(). Each API domain has a dedicated bind*Api(app, apiGroup) function in its own file.
Middleware chain (global, applied to every route)#
Priority-ordered hook.Handler[*core.RequestEvent] instances registered via pbRouter.Bind(...):
| Priority | ID | Purpose |
|---|
| lowest (−40 rel.) | pbActivityLogger | Records request info to aux SQLite log DB |
| −30 rel. | pbPanicRecover | Recovers panics, returns 500 |
| (CORS) | — | CORS headers (configured per ServeConfig.AllowedOrigins) |
| −20 rel. | pbLoadAuthToken | Parses Authorization: <TOKEN> header, sets e.Auth on RequestEvent |
| −10 rel. | pbSecurityHeaders | Adds X-XSS-Protection, X-Content-Type-Options, X-Frame-Options |
| default | pbRateLimit | Token-bucket rate limiting (rules stored in settings) |
| default | pbBodyLimit | Body size cap (default DefaultMaxBodySize) |
| −99999 | pbWWWRedirect | www→non-www redirect for configured domains (registered in Serve()) |
Per-route auth middleware (applied to individual route groups)#
RequireAuth(...collections) — valid JWT from any (or named) auth collectionRequireSuperuserAuth() — alias for RequireAuth("_superusers")RequireSuperuserOrOwnerAuth(ownerIdPathParam) — superuser or matching record ownerRequireSameCollectionContextAuth(collectionPathParam) — auth collection must match path paramRequireGuestOnly() — rejects authenticated requestsBodyLimit(n) — per-route body size override (used for backup upload)SkipSuccessActivityLog() — suppresses activity logging for successful calls
Authentication#
JWT tokens (tools/security). Tokens carry type (auth, file, otp, etc.). The loadAuthToken global middleware auto-populates e.Auth from the Authorization header. Routes then gate access with the per-route auth middlewares above.
Key endpoints#
All routes are under the /api/ prefix.
Records — /api/collections/{collection}/records#
| Method | Path | Auth | Description |
|---|
| GET | /api/collections/{collection}/records | access rules | List records with filtering/sorting/pagination |
| GET | /api/collections/{collection}/records/{id} | access rules | View single record |
| POST | /api/collections/{collection}/records | access rules | Create record (multipart or JSON) |
| PATCH | /api/collections/{collection}/records/{id} | access rules | Update record |
| DELETE | /api/collections/{collection}/records/{id} | access rules | Delete record |
Record Auth — /api/collections/{collection}/#
| Method | Path | Auth | Description |
|---|
| GET | /api/collections/{collection}/auth-methods | guest | List enabled auth methods |
| POST | /api/collections/{collection}/auth-refresh | RequireAuth | Refresh auth token |
| POST | /api/collections/{collection}/auth-with-password | guest | Password authentication |
| POST | /api/collections/{collection}/auth-with-oauth2 | — | OAuth2 authentication |
| POST | /api/collections/{collection}/request-otp | — | Request OTP code |
| POST | /api/collections/{collection}/auth-with-otp | — | OTP authentication |
| POST | /api/collections/{collection}/request-password-reset | — | Request password reset email |
| POST | /api/collections/{collection}/confirm-password-reset | — | Confirm password reset |
| POST | /api/collections/{collection}/request-verification | — | Request email verification |
| POST | /api/collections/{collection}/confirm-verification | — | Confirm email verification |
| POST | /api/collections/{collection}/request-email-change | RequireAuth | Request email change |
| POST | /api/collections/{collection}/confirm-email-change | — | Confirm email change |
| POST | /api/collections/{collection}/impersonate/{id} | RequireSuperuserAuth | Create auth token for another record |
| GET/POST | /api/oauth2-redirect | — | OAuth2 redirect handler (PKCE callback) |
Collections — /api/collections (all require superuser)#
| Method | Path | Description |
|---|
| GET | /api/collections | List collections |
| POST | /api/collections | Create collection |
| GET | /api/collections/{collection} | View collection |
| PATCH | /api/collections/{collection} | Update collection |
| DELETE | /api/collections/{collection} | Delete collection |
| DELETE | /api/collections/{collection}/truncate | Delete all records in collection |
| PUT | /api/collections/import | Bulk import collection schemas |
| GET | /api/collections/meta/scaffolds | List collection type scaffolds |
Settings — /api/settings (all require superuser)#
| Method | Path | Description |
|---|
| GET | /api/settings | List all settings |
| PATCH | /api/settings | Update settings |
| POST | /api/settings/test/s3 | Test S3 connectivity |
| POST | /api/settings/test/email | Send test email |
| POST | /api/settings/apple/generate-client-secret | Generate Apple OAuth2 client secret |
Logs — /api/logs (superuser only)#
| Method | Path | Description |
|---|
| GET | /api/logs | List request logs |
| GET | /api/logs/stats | Request log statistics |
| GET | /api/logs/{id} | View single log entry |
Backups — /api/backups (superuser only)#
| Method | Path | Description |
|---|
| GET | /api/backups | List backup files |
| POST | /api/backups | Create backup |
| POST | /api/backups/upload | Upload backup (no body limit) |
| GET | /api/backups/{key} | Download backup (via file token) |
| DELETE | /api/backups/{key} | Delete backup |
| POST | /api/backups/{key}/restore | Restore from backup |
Realtime — /api/realtime#
| Method | Path | Description |
|---|
| GET | /api/realtime | SSE connect (long-poll, no activity log) |
| POST | /api/realtime | Update SSE subscriptions |
Files — /api/files#
| Method | Path | Description |
|---|
| POST | /api/files/token | Generate short-lived file access token |
| GET | /api/files/{collection}/{recordId}/{filename} | Download/serve file |
Crons — /api/crons (superuser only)#
| Method | Path | Description |
|---|
| GET | /api/crons | List registered cron jobs |
| POST | /api/crons/{id} | Manually trigger a cron job |
Batch — /api/batch#
| Method | Path | Description |
|---|
| POST | /api/batch | Execute a transaction of multiple record operations (create/update/upsert/delete) |
Health — /api/health#
| Method | Path | Description |
|---|
| GET | /api/health | Health check endpoint |
Admin UI — /_/{path...}#
Serves the embedded Svelte Admin SPA from ui/dist/ (Go embed, go:embed), with Cache-Control and CSP headers. Gzip-compressed.
CLI#
- Framework: Cobra (
github.com/spf13/cobra) - Binary entry point:
examples/base/main.go (the reference production binary)
Command structure#
pocketbase
├── serve [domain(s)] Start the HTTP/HTTPS server
│ --http <addr> HTTP listen address (default 127.0.0.1:8090)
│ --https <addr> HTTPS listen address (enables autocert TLS)
│ --origins <origins> CORS allowed origins (default *)
│
├── superuser Manage superuser accounts
│ ├── upsert <email> <pw> Create or update superuser
│ ├── create <email> <pw> Create new superuser
│ ├── update <email> <pw> Change superuser password
│ ├── delete <email> Delete superuser
│ └── otp <email> Generate OTP for superuser
│
├── migrate (plugin: migratecmd)
│ Apply pending DB migrations; generate migration stubs
│
└── update (plugin: ghupdate)
Self-update binary from GitHub releases
Flag patterns#
- Global persistent flags on root command:
--dir (data directory), --dev (dev mode), --encryptionEnv (settings AES key env var), --queryTimeout. - Each Cobra plugin (
migratecmd, ghupdate, jsvm) registers additional PersistentFlags on RootCmd when Register() is called. - No environment variable binding in PocketBase itself; the
--encryptionEnv flag takes an env var name, not the value directly.
Plugin / Extension system#
Mechanism#
Hook-based, using the generic tools/hook.Hook[T Resolver]. All extension points are lifecycle hooks on core.App. The same hook API is used by:
- Go extensions — library users call
app.OnXxx().BindFunc(...) before app.Start(). - JavaScript extensions —
plugins/jsvm registers Go-side hook handlers that invoke JS callbacks from files in pb_hooks/.
Extension points (hook categories)#
| Category | Example hooks |
|---|
| Lifecycle | OnBootstrap, OnServe, OnTerminate |
| Record CRUD | OnRecordCreate, OnRecordUpdate, OnRecordDelete, OnRecordValidate, OnRecordCreateRequest, OnRecordAfterCreateSuccess, … |
| Model CRUD | OnModelCreate, OnModelUpdate, OnModelDelete, OnModelAfterCreateSuccess, … |
| Collection | OnCollectionCreate, OnCollectionUpdate, OnCollectionDelete, … |
| Auth | OnRecordAuthRequest, OnRecordAuthWithPassword, OnRecordAuthWithOAuth2, OnRecordAuthWithOTP, … |
| Mailer | OnMailerSend, OnMailerRecordPasswordResetSend, … |
| Settings | OnSettingsReload, OnSettingsUpdate |
| Realtime | OnRealtimeConnect, OnRealtimeSubscribe, OnRealtimeMessageSend |
| Backup | OnBackupCreate, OnBackupRestore |
| Request | OnServe — fires before HTTP listener starts; plugins attach routes here via e.Router |
OnServe — the primary route extension point#
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
e.Router.GET("/custom/{name}", func(re *core.RequestEvent) error {
return re.JSON(200, map[string]string{"hello": re.Request.PathValue("name")})
})
return e.Next()
})
ServeEvent.Router is the same *router.Router[*core.RequestEvent] instance used for all built-in routes, so custom routes get the full middleware stack automatically.
JavaScript extension entry points (plugins/jsvm)#
- Files matching
*.pb.js or *.pb.ts in pb_hooks/ are loaded and executed. - The JS runtime exposes the full Go hook API:
onRecordCreateRequest(fn), onServe(fn), routerAdd("GET", "/path", handler), etc. - TypeScript type definitions are pre-generated in
plugins/jsvm/internal/types/ for IDE autocomplete. - A pool of pre-warmed
goja.Runtime instances avoids per-request cold starts.
Standard middleware wrappers (library API)#
Two convenience functions allow embedding standard Go HTTP middleware into the PocketBase hook chain:
apis.WrapStdHandler(h http.Handler) func(*core.RequestEvent) errorapis.WrapStdMiddleware(m func(http.Handler) http.Handler) func(*core.RequestEvent) error
Library API#
PocketBase is designed to be used as a Go library. Users write a main.go (~20 lines) that:
- Creates a
pocketbase.New() instance (which embeds core.App) - Registers plugins and hooks
- Calls
app.Start()
Public packages exported for library use#
| Package | Purpose |
|---|
github.com/pocketbase/pocketbase | Top-level PocketBase struct; entry point for library users |
github.com/pocketbase/pocketbase/core | App interface, BaseApp, all model types (Record, Collection, etc.), RequestEvent |
github.com/pocketbase/pocketbase/apis | NewRouter, Serve, ServeConfig, all middleware constructors, Static, WrapStdHandler |
github.com/pocketbase/pocketbase/cmd | NewServeCommand, NewSuperuserCommand — Cobra command constructors |
github.com/pocketbase/pocketbase/tools/hook | Hook[T], Handler[T] — the extension primitive |
github.com/pocketbase/pocketbase/tools/router | Router[T], RouterGroup[T], ApiError helpers |
github.com/pocketbase/pocketbase/plugins/jsvm | Register(app, Config) — JSVM plugin |
github.com/pocketbase/pocketbase/plugins/migratecmd | Register(app, rootCmd, Config) — migration CLI plugin |
github.com/pocketbase/pocketbase/plugins/ghupdate | Register(app, rootCmd, Config) — self-update plugin |
github.com/pocketbase/pocketbase/forms | High-level form validators (used internally; usable from library code) |
github.com/pocketbase/pocketbase/mails | Email sending helpers |
github.com/pocketbase/pocketbase/migrations | Built-in system migrations (auto-registered) |
API style#
- Primarily interface + concrete struct (
core.App / core.BaseApp). - Hooks use a generic middleware chain — callers
BindFunc(func(e *T) error) or Bind(&hook.Handler[*T]{...}). - Configuration for plugins is via config structs (
jsvm.Config, apis.ServeConfig, etc.). - No functional options; no builder pattern. Explicit struct fields throughout.
Backward compatibility#
No explicit versioning strategy in code. The project signals stability via semver git tags. The core.App interface is very large (~150 methods) — additions are backward-compatible for callers, but implementations (e.g. test stubs) must be updated. The godoc comment on core.App explicitly notes it is not intended to be implemented by third parties, which avoids the ISP problem in practice.