### PocketBase Go Framework Minimal Example Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md This Go code demonstrates how to use PocketBase as a framework to build a custom application. It registers a new GET route '/hello' that returns 'Hello world!'. Ensure Go 1.23+ is installed. ```go package main import ( "log" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" ) func main() { app := pocketbase.New() app.OnServe().BindFunc(func(se *core.ServeEvent) error { // registers new "GET /hello" route se.Router.GET("/hello", func(re *core.RequestEvent) error { return re.String(200, "Hello world!") }) return se.Next() }) if err := app.Start(); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Install Dependencies and Run Dev Server Source: https://github.com/fondoger/pocketbase/blob/postgres/ui/README.md Installs project dependencies and starts a development server with hot reloading. Ensure Node.js and npm are installed. ```sh npm install npm run dev ``` -------------------------------- ### Start PocketBase with PostgreSQL Source: https://context7.com/fondoger/pocketbase/llms.txt Run PocketBase backed by PostgreSQL by setting the POSTGRES_URL environment variable before invoking the binary. This example first starts a PostgreSQL container using Docker. ```sh # Start a PostgreSQL container docker run -d \ --name postgres \ -p 5432:5432 \ -e POSTGRES_USER=user \ -e POSTGRES_PASSWORD=pass \ -v ./pg_data:/var/lib/postgresql/data \ postgres:alpine # Start PocketBase — only difference vs upstream is POSTGRES_URL export POSTGRES_URL="postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable" ./pocketbase serve # → server listening on http://127.0.0.1:8090 ``` -------------------------------- ### Start PocketBase HTTP/HTTPS Server Source: https://context7.com/fondoger/pocketbase/llms.txt Use the `serve` command to start the PocketBase server. Options include specifying the HTTP/HTTPS address, enabling automatic TLS with domain names, setting a path prefix, or providing a custom PostgreSQL connection string. ```sh ./pocketbase serve ``` ```sh ./pocketbase serve --http=0.0.0.0:8080 ``` ```sh ./pocketbase serve example.com www.example.com \ --https=0.0.0.0:443 \ --http=0.0.0.0:80 ``` ```sh ./pocketbase serve --pathPrefix=/pb --http=127.0.0.1:8090 ``` ```sh ./pocketbase serve \ --postgresUrl="postgres://user:pass@db.internal:5432/postgres?sslmode=require" \ --postgresDataDB="prod-data" \ --postgresAuxDB="prod-logs" ``` -------------------------------- ### Run PocketBase Go Application Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Navigate to the examples/base directory and run the Go application to start a local PocketBase server. This server includes the embedded Admin UI. ```bash go run main.go serve ``` -------------------------------- ### Set PostgreSQL URL and Serve PocketBase Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Export the PostgreSQL connection URL as an environment variable and then start the PocketBase server. This is the basic setup for running PocketBase with PostgreSQL. ```sh export POSTGRES_URL=postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable ./pocketbase serve ``` -------------------------------- ### Install Admin UI Dependencies Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Navigate to the 'ui' directory and install the necessary Node.js dependencies for the Admin UI using npm. This is a prerequisite for running the development server. ```bash npm install ``` -------------------------------- ### Run PocketBase Executable Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Start the created PocketBase executable after building it. ```bash ./base serve ``` -------------------------------- ### Start Admin UI Development Server Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Start Vite's development server for the Admin UI. This allows for live reloading of changes made to the Admin UI components. ```bash npm run dev ``` -------------------------------- ### CLI: serve Command Source: https://context7.com/fondoger/pocketbase/llms.txt Starts the PocketBase HTTP/HTTPS web server. Supports various configurations including custom addresses, automatic TLS, path prefixes, and custom PostgreSQL connections. ```APIDOC ## CLI: `serve` Command Start the HTTP/HTTPS web server with optional domain-based automatic TLS. ```sh # Development (default localhost:8090) ./pocketbase serve # Custom HTTP address ./pocketbase serve --http=0.0.0.0:8080 # Production with automatic TLS (Let's Encrypt) ./pocketbase serve example.com www.example.com \ --https=0.0.0.0:443 \ --http=0.0.0.0:80 # With path prefix behind nginx ./pocketbase serve --pathPrefix=/pb --http=127.0.0.1:8090 # With custom PostgreSQL connection ./pocketbase serve \ --postgresUrl="postgres://user:pass@db.internal:5432/postgres?sslmode=require" \ --postgresDataDB="prod-data" \ --postgresAuxDB="prod-logs" ``` ``` -------------------------------- ### PocketBase Go Application Initialization Source: https://context7.com/fondoger/pocketbase/llms.txt Initialize a PocketBase application in Go using `pocketbase.NewWithConfig()`, allowing programmatic configuration of defaults like the PostgreSQL URL and data directory. This example also registers a custom HTTP route. ```go package main import ( "log" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" ) func main() { app := pocketbase.NewWithConfig(pocketbase.Config{ DefaultPostgresURL: "postgres://user:pass@localhost:5432/postgres?sslmode=disable", DefaultPostgresDataDb: "myapp-data", DefaultPostgresAuxDb: "myapp-logs", DefaultDataDir: "./pb_data", HideStartBanner: false, }) // Register a custom GET /hello route on server start app.OnServe().BindFunc(func(se *core.ServeEvent) error { se.Router.GET("/hello", func(re *core.RequestEvent) error { return re.String(200, "Hello world!") }) return se.Next() }) // Start registers serve + superuser commands, then executes if err := app.Start(); err != nil { log.Fatal(err) } } // Run: go run main.go serve // Run: go run main.go serve --postgresUrl="postgres://..." --http=0.0.0.0:8080 ``` -------------------------------- ### Build Production Bundle Source: https://github.com/fondoger/pocketbase/blob/postgres/ui/README.md Generates a production-ready bundle for deployment in the dist/ directory. Ensure Node.js and npm are installed. ```sh npm run build ``` -------------------------------- ### Run PostgreSQL Docker Container Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Starts a PostgreSQL Docker container. Ensure to map the port and persist data using a volume. This is a prerequisite for running PocketBase with PostgreSQL. ```sh docker run -d \ --name postgres \ -p 5432:5432 \ -e POSTGRES_USER=user \ -e POSTGRES_PASSWORD=pass \ -v ./pg_data:/var/lib/postgresql/data \ postgres:alpine ``` -------------------------------- ### Realtime Subscriptions via SSE Source: https://context7.com/fondoger/pocketbase/llms.txt Subscribe to record change events using Server-Sent Events (SSE). This example shows connecting to the stream, setting subscriptions, and receiving events. ```sh # Connect to the SSE stream curl -N "http://127.0.0.1:8090/api/realtime" # → data: {"clientId": "client_abc123"} (initial connection event) # Set subscriptions (in a separate request) curl -X POST "http://127.0.0.1:8090/api/realtime" \ -H "Content-Type: application/json" \ -d '{"clientId": "client_abc123", "subscriptions": ["posts", "posts/abc123"]}' # The SSE stream now receives events like: # data: {"action": "create", "record": { "id": "xyz", "title": "New Post", ... }} # data: {"action": "update", "record": { "id": "abc123", "status": "published", ... }} # data: {"action": "delete", "record": { "id": "abc123", ... }} ``` -------------------------------- ### Run PocketBase Docker Container with PostgreSQL Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Starts the PocketBase Docker container, connecting it to a PostgreSQL database. It's recommended to use a specific version tag instead of 'latest' in production. This configuration includes setting the HTTP address, data directory, and the PostgreSQL connection URL. ```sh docker run -d \ --network=host \ --name pocketbase \ -v ./pb_data:/data \ -e PB_HTTP_ADDR=127.0.0.1:8090 \ -e PB_DATA_DIR="/data" \ -e POSTGRES_URL="postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable" \ ghcr.io/fondoger/pocketbase:latest ``` -------------------------------- ### List Records with Filtering and Sorting (REST API) Source: https://context7.com/fondoger/pocketbase/llms.txt Use `GET /api/collections/{collection}/records` to list records. Supports filtering, sorting, pagination, and expanding relation fields. Access is governed by the collection's `listRule`. ```sh curl "http://127.0.0.1:8090/api/collections/posts/records" ``` ```sh curl "http://127.0.0.1:8090/api/collections/posts/records?filter=(status='published')&sort=-created&page=1&perPage=20" ``` ```sh curl "http://127.0.0.1:8090/api/collections/posts/records?expand=author" ``` ```sh curl -H "Authorization: Bearer eyJ..." \ "http://127.0.0.1:8090/api/collections/posts/records" ``` -------------------------------- ### Fetch Single Record by ID (REST API) Source: https://context7.com/fondoger/pocketbase/llms.txt Retrieve a single record using its ID with `GET /api/collections/{collection}/records/{id}`. Supports expanding relation fields. ```sh curl "http://127.0.0.1:8090/api/collections/posts/records/abc123" ``` ```sh curl "http://127.0.0.1:8090/api/collections/posts/records/abc123?expand=author,tags" ``` -------------------------------- ### Initialize Go Module Dependencies Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md After creating the main.go file for your PocketBase Go application, initialize the Go module dependencies. ```bash go mod init myapp && go mod tidy ``` -------------------------------- ### Go: Querying Records with app.FindRecordById(), app.FindAllRecords(), and app.RecordQuery() Source: https://context7.com/fondoger/pocketbase/llms.txt Fetch records using typed helpers like `FindRecordById`, `FindFirstRecordByFilter`, `FindAllRecords`, or the flexible `RecordQuery()` builder for advanced filtering and sorting. ```go import "github.com/pocketbase/dbx" // Find a single record by ID post, err := app.FindRecordById("posts", "abc123") if err != nil { // record not found or DB error } // Find the first matching record post, err = app.FindFirstRecordByFilter("posts", "status = 'published' && author = {:author}", dbx.Params{ "author": "usr001", }) // Find all matching records posts, err := app.FindAllRecords("posts", dbx.HashExp{"status": "published"}, ) // Advanced query with the query builder var posts []*core.Record err = app.RecordQuery("posts"). AndWhere(dbx.HashExp{"status": "published"}). OrderBy("created DESC"). Limit(10). All(&posts) ``` -------------------------------- ### Build PocketBase Standalone Executable from Source Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Build a minimal standalone executable for PocketBase from the source code, similar to the prebuilt releases. This command is run from the 'examples/base' directory. ```bash GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build ``` -------------------------------- ### REST API: Single Record — GET /api/collections/{collection}/records/{id} Source: https://context7.com/fondoger/pocketbase/llms.txt Fetches a single record from a collection by its unique ID. Supports expanding relation fields. ```APIDOC ## REST API: Single Record — `GET /api/collections/{collection}/records/{id}` Fetch a single record by its ID. ```sh curl "http://127.0.0.1:8090/api/collections/posts/records/abc123" # { "id": "abc123", "title": "Hello", "status": "published", ... } # With relation expansion curl "http://127.0.0.1:8090/api/collections/posts/records/abc123?expand=author,tags" ``` ``` -------------------------------- ### Run PocketBase Tests Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Execute all unit and integration tests for PocketBase using the standard Go testing package or the provided Makefile. This ensures your changes do not break existing functionality. ```bash go test ./... ``` ```bash make test ``` -------------------------------- ### REST API: Records CRUD — GET /api/collections/{collection}/records Source: https://context7.com/fondoger/pocketbase/llms.txt Lists records from a specified collection. Supports filtering, sorting, pagination, and expanding relation fields. Access is governed by the collection's `listRule`. ```APIDOC ## REST API: Records CRUD — `GET /api/collections/{collection}/records` List records from a collection with filtering, sorting, and pagination. Access is controlled by the collection's `listRule`. ```sh # List all records (public collection) curl "http://127.0.0.1:8090/api/collections/posts/records" # Filter, sort, and paginate curl "http://127.0.0.1:8090/api/collections/posts/records?filter=(status='published')&sort=-created&page=1&perPage=20" # Expand a relation field curl "http://127.0.0.1:8090/api/collections/posts/records?expand=author" # Authenticated request (bearer token) curl -H "Authorization: Bearer eyJ..." \ "http://127.0.0.1:8090/api/collections/posts/records" # Expected response # { # "page": 1, "perPage": 20, "totalItems": 42, "totalPages": 3, # "items": [ # { "id": "abc123", "collectionId": "...", "title": "Hello", "status": "published", "created": "...", "updated": "..." } # ] # } ``` ``` -------------------------------- ### Run PocketBase Tests Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Execute all unit and integration tests for PocketBase using the standard Go testing command. ```bash go test ./... ``` -------------------------------- ### Programmatic Record Writes with app.Save() and app.Delete() Source: https://context7.com/fondoger/pocketbase/llms.txt Demonstrates how to create, update, and delete records directly from Go code using `app.Save()` and `app.Delete()`. This process triggers all associated hooks and validations. ```APIDOC ## Go API: `app.Save()` / `app.Delete()` — Programmatic Record Writes Create, update, and delete records directly from Go code, triggering all hooks and validations. ```go app.OnServe().BindFunc(func(se *core.ServeEvent) error { se.Router.POST("/api/custom/seed", func(re *core.RequestEvent) error { col, err := re.App.FindCachedCollectionByNameOrId("posts") if err != nil { return re.NotFoundError("Collection not found", err) } record := core.NewRecord(col) record.Set("title", "Seeded Post") record.Set("status", "published") record.Set("content", "Auto-generated content") if err := re.App.Save(record); err != nil { return re.BadRequestError("Failed to save", err) } // Update the same record record.Set("title", "Updated Seeded Post") if err := re.App.Save(record); err != nil { return re.InternalServerError("Failed to update", err) } // Delete it if err := re.App.Delete(record); err != nil { return re.InternalServerError("Failed to delete", err) } return re.JSON(http.StatusOK, map[string]string{"status": "done"}) }).Bind(apis.RequireSuperuserAuth()) return se.Next() }) ``` ``` -------------------------------- ### Clone PocketBase Repository Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Clone your fork of the PocketBase repository to begin local development. Ensure you have a GitHub account and have forked the main repository. ```bash git clone https://github.com/your_username/pocketbase.git ``` -------------------------------- ### List Authentication Methods Source: https://context7.com/fondoger/pocketbase/llms.txt Retrieve a list of all authentication methods configured for a specific collection, including their enabled status and relevant details. ```sh curl "http://127.0.0.1:8090/api/collections/users/auth-methods" # { # "password": { "enabled": true, "identityFields": ["email"] }, # "oauth2": { "enabled": true, "providers": [{ "name": "google", "displayName": "Google", "authURL": "..." }] }, # "otp": { "enabled": false }, # "mfa": { "enabled": false } # } ``` -------------------------------- ### Run GolangCI Linter Source: https://github.com/fondoger/pocketbase/blob/postgres/CONTRIBUTING.md Apply the golangci-lint linter to your Go code changes using the specified configuration file. This helps maintain code quality and consistency. ```bash golangci-lint run -c ./golangci.yml ./... ``` ```bash make lint ``` -------------------------------- ### Querying Records with app.FindRecordById(), app.FindAllRecords(), and app.RecordQuery() Source: https://context7.com/fondoger/pocketbase/llms.txt Provides methods to fetch records from the database using typed helpers or a raw query builder. Supports finding single records, first matching records, all matching records, and advanced querying. ```APIDOC ## Go API: `app.FindRecordById()` / `app.FindAllRecords()` / `app.RecordQuery()` — Querying Records Fetch records from the database using typed helpers or a raw query builder. ```go import "github.com/pocketbase/dbx" // Find a single record by ID post, err := app.FindRecordById("posts", "abc123") if err != nil { // record not found or DB error } // Find the first matching record post, err = app.FindFirstRecordByFilter("posts", "status = 'published' && author = {:author}", dbx.Params{ "author": "usr001", }) // Find all matching records posts, err := app.FindAllRecords("posts", dbx.HashExp{"status": "published"}, ) // Advanced query with the query builder var posts []*core.Record err = app.RecordQuery("posts"). AndWhere(dbx.HashExp{"status": "published"}). OrderBy("created DESC"). Limit(10). All(&posts) ``` ``` -------------------------------- ### Run PocketBase as Standalone App Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md To run PocketBase as a standalone application, download the prebuilt executable for your platform and run it from the extracted directory. ```bash ./pocketbase serve ``` -------------------------------- ### Log Record Creation Success with OnRecordAfterCreateSuccess Hook Source: https://context7.com/fondoger/pocketbase/llms.txt Send a notification after a post is created by logging the event details. ```go app.OnRecordAfterCreateSuccess("posts").BindFunc(func(e *core.RecordEvent) error { // Send a notification after a post is created app.Logger().Info("New post created", "id", e.Record.Id, "title", e.Record.GetString("title")) return e.Next() }) ``` -------------------------------- ### Build Statically Linked PocketBase Executable Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Build a statically linked executable for your PocketBase Go application. This command disables CGO, which is often required for cross-compilation. ```bash CGO_ENABLED=0 go build ``` -------------------------------- ### Go: Sending Emails with app.NewMailClient() Source: https://context7.com/fondoger/pocketbase/llms.txt Send transactional emails using the `app.NewMailClient()` which utilizes the configured SMTP settings. Ensure the `mail` package is imported. ```go app.OnRecordAfterCreateSuccess("users").BindFunc(func(e *core.RecordEvent) error { mailer := app.NewMailClient() message := &mailer.Message{ From: mail.Address{Name: "MyApp", Address: "no-reply@myapp.com"}, To: []mail.Address{{Address: e.Record.Email()}}, Subject: "Welcome to MyApp!", HTML: "
Thanks for registering, " + e.Record.GetString("name") + "!
", } if err := mailer.Send(message); err != nil { app.Logger().Error("Failed to send welcome email", "err", err) } return e.Next() }) ``` -------------------------------- ### Request OTP and Authenticate with OTP Source: https://context7.com/fondoger/pocketbase/llms.txt Two-step authentication process. First, request a one-time code via email, then authenticate using the received OTP ID and password. ```sh # Step 1: request OTP (sent via email) curl -X POST "http://127.0.0.1:8090/api/collections/users/request-otp" \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' # Response: { "otpId": "otp_abc123" } ``` ```sh # Step 2: authenticate with the OTP code curl -X POST "http://127.0.0.1:8090/api/collections/users/auth-with-otp" \ -H "Content-Type: application/json" \ -d '{"otpId": "otp_abc123", "password": "847291"}' # Response: { "token": "eyJ...", "record": { ... } } ``` -------------------------------- ### Auth Methods Source: https://context7.com/fondoger/pocketbase/llms.txt Lists all authentication methods configured for a specific collection. ```APIDOC ## GET /api/collections/{collection}/auth-methods ### Description Retrieves a list of all authentication methods (e.g., password, OAuth2, OTP) enabled for a given collection. ### Method GET ### Endpoint /api/collections/{collection}/auth-methods ### Response #### Success Response (200 OK) - **password** (object) - Details about password authentication, including enabled status and identity fields. - **oauth2** (object) - Details about OAuth2 authentication, including enabled status and available providers. - **otp** (object) - Details about OTP authentication, including enabled status. - **mfa** (object) - Details about MFA authentication, including enabled status. ``` -------------------------------- ### Go: Programmatic Record Writes with app.Save() and app.Delete() Source: https://context7.com/fondoger/pocketbase/llms.txt Use `app.Save()` to create or update records and `app.Delete()` to remove them. This method triggers all associated hooks and validations. ```go app.OnServe().BindFunc(func(se *core.ServeEvent) error { se.Router.POST("/api/custom/seed", func(re *core.RequestEvent) error { col, err := re.App.FindCachedCollectionByNameOrId("posts") if err != nil { return re.NotFoundError("Collection not found", err) } record := core.NewRecord(col) record.Set("title", "Seeded Post") record.Set("status", "published") record.Set("content", "Auto-generated content") if err := re.App.Save(record); err != nil { return re.BadRequestError("Failed to save", err) } // Update the same record record.Set("title", "Updated Seeded Post") if err := re.App.Save(record); err != nil { return re.InternalServerError("Failed to update", err) } // Delete it if err := re.App.Delete(record); err != nil { return re.InternalServerError("Failed to delete", err) } return re.JSON(http.StatusOK, map[string]string{"status": "done"}) }).Bind(apis.RequireSuperuserAuth()) return se.Next() }) ``` -------------------------------- ### Register Custom Routes and Middleware with OnServe Hook Source: https://context7.com/fondoger/pocketbase/llms.txt Register custom HTTP routes and middleware by binding to the `OnServe` hook. This runs once at server startup. ```go package main import ( "log" "net/http" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" ) func main() { app := pocketbase.New() app.OnServe().BindFunc(func(se *core.ServeEvent) error { // Public route se.Router.GET("/api/custom/ping", func(re *core.RequestEvent) error { return re.JSON(http.StatusOK, map[string]string{"ping": "pong"}) }) // Protected route requiring any authenticated user se.Router.GET("/api/custom/me", func(re *core.RequestEvent) error { return re.JSON(http.StatusOK, re.Auth) }).Bind(apis.RequireAuth()) // Route requiring superuser auth se.Router.POST("/api/custom/admin-action", func(re *core.RequestEvent) error { return re.JSON(http.StatusOK, map[string]bool{"done": true}) }).Bind(apis.RequireSuperuserAuth()) return se.Next() }) if err := app.Start(); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Go: Database Transactions with app.RunInTransaction() Source: https://context7.com/fondoger/pocketbase/llms.txt Execute multiple database operations atomically using `app.RunInTransaction()`. All hooks and validations are active within the transaction, and it automatically rolls back on error. ```go err := app.RunInTransaction(func(txApp core.App) error { col, err := txApp.FindCachedCollectionByNameOrId("orders") if err != nil { return err } order := core.NewRecord(col) order.Set("status", "pending") order.Set("total", 99.99) if err := txApp.Save(order); err != nil { return err // automatically rolls back } itemCol, err := txApp.FindCachedCollectionByNameOrId("order_items") if err != nil { return err } item := core.NewRecord(itemCol) item.Set("orderId", order.Id) item.Set("product", "Widget") item.Set("qty", 2) if err := txApp.Save(item); err != nil { return err // automatically rolls back both saves } return nil // commits both saves }) ``` -------------------------------- ### View PocketBase Docker Logs Source: https://github.com/fondoger/pocketbase/blob/postgres/README.md Streams the logs from the PocketBase Docker container in real-time. This is useful for monitoring the server and retrieving the admin password reset link upon initial startup. ```sh docker logs -f pocketbase ``` -------------------------------- ### Custom Routes and Middleware (OnServe Hook) Source: https://context7.com/fondoger/pocketbase/llms.txt Register custom HTTP routes and middleware by binding to the OnServe hook, which runs once at server startup. ```APIDOC ## Custom Routes with OnServe Hook ### Description Allows registration of custom HTTP routes and middleware during server startup using the `OnServe` hook. ### Example Routes #### Public Route ##### GET /api/custom/ping - **Description**: A simple public endpoint that returns a ping-pong response. - **Method**: GET - **Endpoint**: /api/custom/ping - **Response**: `{"ping": "pong"}` #### Protected Route (Requires Authentication) ##### GET /api/custom/me - **Description**: An endpoint that requires any authenticated user and returns the authenticated user's data. - **Method**: GET - **Endpoint**: /api/custom/me - **Authentication**: Requires authentication (`apis.RequireAuth()`). - **Response**: Returns the authenticated user object. #### Protected Route (Requires Superuser) ##### POST /api/custom/admin-action - **Description**: An endpoint that requires superuser privileges to perform an admin action. - **Method**: POST - **Endpoint**: /api/custom/admin-action - **Authentication**: Requires superuser authentication (`apis.RequireSuperuserAuth()`). - **Response**: `{"done": true}` ``` -------------------------------- ### Docker Deployment for Horizontal Scaling Source: https://context7.com/fondoger/pocketbase/llms.txt Deploy two independent PocketBase instances that share the same PostgreSQL backend and sync realtime events via the bridge. Each instance is configured with its own HTTP address and data directory. ```sh # Instance 1 — port 8091 docker run -d \ --network=host \ --name pocketbase-1 \ -v ./pb_data_1:/data \ -e PB_HTTP_ADDR=127.0.0.1:8091 \ -e PB_DATA_DIR="/data" \ -e POSTGRES_URL="postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable" \ ghcr.io/fondoger/pocketbase:latest # Instance 2 — port 8092 docker run -d \ --network=host \ --name pocketbase-2 \ -v ./pb_data_2:/data \ -e PB_HTTP_ADDR=127.0.0.1:8092 \ -e PB_DATA_DIR="/data" \ -e POSTGRES_URL="postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable" \ ghcr.io/fondoger/pocketbase:latest # Both instances share the same pb-data and pb-auxiliary PostgreSQL databases. # Realtime bridge is enabled by default (PB_REALTIME_BRIDGE=true). ``` -------------------------------- ### CLI: superuser Command Source: https://context7.com/fondoger/pocketbase/llms.txt Manages superuser (admin) accounts directly from the command line, allowing creation, updating, deletion, and OTP generation. ```APIDOC ## CLI: `superuser` Command Manage superuser (admin) accounts without using the Admin UI. ```sh # Create or update a superuser ./pocketbase superuser upsert admin@example.com MySecurePass123 # Create a new superuser (fails if email already exists) ./pocketbase superuser create admin@example.com MySecurePass123 # Change an existing superuser's password ./pocketbase superuser update admin@example.com NewPassword456 # Delete a superuser ./pocketbase superuser delete admin@example.com # Generate a one-time password (OTP) for superuser login ./pocketbase superuser otp admin@example.com # Output: # ✓ Successfully created OTP for superuser "admin@example.com": # ├─ Id: abc123xyz # ├─ Pass: 847291 # └─ Valid: 180s ``` ``` -------------------------------- ### Realtime Subscriptions with PocketBase SDK (JavaScript) Source: https://context7.com/fondoger/pocketbase/llms.txt Subscribe to record changes in realtime using the official PocketBase JavaScript SDK. Supports subscribing to all changes in a collection or to a specific record. ```js import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); // Subscribe to all changes in the "posts" collection pb.collection('posts').subscribe('*', (e) => { console.log(e.action); // "create" | "update" | "delete" console.log(e.record); }); // Subscribe to a specific record pb.collection('posts').subscribe('abc123', (e) => { console.log('Post updated:', e.record); }); // Unsubscribe pb.collection('posts').unsubscribe(); ``` -------------------------------- ### Schedule Daily Session Cleanup Job Source: https://context7.com/fondoger/pocketbase/llms.txt Schedule a daily cron job to run at midnight UTC to clean up expired sessions by finding and deleting them. ```go app.OnServe().BindFunc(func(se *core.ServeEvent) error { // Run daily at midnight UTC app.Cron().MustAdd("cleanupExpiredSessions", "0 0 * * *", func() { app.Logger().Info("Running cleanup...") records, err := app.FindAllRecords("sessions", dbx.HashExp{"expired": true}, ) if err != nil { app.Logger().Error("Cleanup error", "err", err) return } for _, r := range records { app.Delete(r) } app.Logger().Info("Cleanup done", "deleted", len(records)) }) // Run every 5 minutes app.Cron().MustAdd("heartbeat", "*/5 * * * *", func() { app.Logger().Info("Heartbeat tick") }) return se.Next() }) ``` -------------------------------- ### Realtime Subscriptions Source: https://context7.com/fondoger/pocketbase/llms.txt Enables subscribing to record change events (create, update, delete) using Server-Sent Events (SSE). ```APIDOC ## GET /api/realtime ### Description Establishes a Server-Sent Events (SSE) stream to receive real-time updates for record changes. ### Method GET ### Endpoint /api/realtime ### Response #### Success Response (200 OK) - The response is a stream of events. The initial event contains a `clientId`. ## POST /api/realtime ### Description Configures subscriptions for the real-time SSE stream, specifying which collections or records to listen to. ### Method POST ### Endpoint /api/realtime ### Parameters #### Request Body - **clientId** (string) - Required - The client ID obtained from the initial SSE connection. - **subscriptions** (array) - Required - A list of subscriptions. Can include collection names (e.g., "posts") or specific record IDs (e.g., "posts/abc123"). ### Request Example ```json { "clientId": "client_abc123", "subscriptions": ["posts", "posts/abc123"] } ``` ### Response #### Success Response (204 No Content) ### SSE Event Examples ``` data: {"clientId": "client_abc123"} (initial connection event) data: {"action": "create", "record": { "id": "xyz", "title": "New Post", ... }} data: {"action": "update", "record": { "id": "abc123", "status": "published", ... }} data: {"action": "delete", "record": { "id": "abc123", ... }} ``` ``` -------------------------------- ### Integrate Standard net/http Handler with PocketBase Source: https://context7.com/fondoger/pocketbase/llms.txt Use apis.WrapStdHandler to integrate a standard Go http.Handler into PocketBase routes. This allows using existing http.Handler implementations within the PocketBase framework. ```go import ( "net/http" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" ) app.OnServe().BindFunc(func(se *core.ServeEvent) error { // Wrap a standard http.Handler stdHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("standard handler")) }) se.Router.GET("/api/custom/std", apis.WrapStdHandler(stdHandler)) // Wrap a standard middleware (e.g., a third-party rate limiter) myMiddleware := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Custom-Header", "value") next.ServeHTTP(w, r) }) } se.Router.GET("/api/custom/wrapped", func(re *core.RequestEvent) error { return re.String(200, "ok") }).Bind(apis.WrapStdMiddleware(myMiddleware)) return se.Next() }) ``` -------------------------------- ### Auth with OTP Source: https://context7.com/fondoger/pocketbase/llms.txt Handles two-step OTP authentication by first requesting a one-time code and then authenticating with it. ```APIDOC ## POST /api/collections/{collection}/request-otp ### Description Requests a one-time code (OTP) to be sent to the user's email for two-step authentication. ### Method POST ### Endpoint /api/collections/{collection}/request-otp ### Parameters #### Request Body - **email** (string) - Required - The email address to send the OTP to. ### Request Example ```json { "email": "user@example.com" } ``` ### Response #### Success Response (204 No Content) ## POST /api/collections/{collection}/auth-with-otp ### Description Authenticates a user using a previously requested OTP code and their password. ### Method POST ### Endpoint /api/collections/{collection}/auth-with-otp ### Parameters #### Request Body - **otpId** (string) - Required - The ID of the OTP request. - **password** (string) - Required - The user's password. ### Request Example ```json { "otpId": "otp_abc123", "password": "847291" } ``` ### Response #### Success Response (200 OK) - **token** (string) - Authentication token. - **record** (object) - The authenticated user record. ``` -------------------------------- ### Manage PocketBase Superuser Accounts Source: https://context7.com/fondoger/pocketbase/llms.txt The `superuser` command allows managing admin accounts via the CLI. Operations include creating, updating passwords, deleting, and generating one-time passwords (OTPs) for superusers. ```sh ./pocketbase superuser upsert admin@example.com MySecurePass123 ``` ```sh ./pocketbase superuser create admin@example.com MySecurePass123 ``` ```sh ./pocketbase superuser update admin@example.com NewPassword456 ``` ```sh ./pocketbase superuser delete admin@example.com ``` ```sh ./pocketbase superuser otp admin@example.com ``` -------------------------------- ### Access RealtimeBridge Instance in PocketBase Source: https://context7.com/fondoger/pocketbase/llms.txt The RealtimeBridge is auto-initialized when enabled. Access its instance via the app store within an OnServe hook. The bridge synchronizes SSE events across multiple server instances. ```go import "github.com/pocketbase/pocketbase/apis" app.OnServe().BindFunc(func(se *core.ServeEvent) error { bridge, ok := app.Store().Get(apis.RealtimeBridgeInstanceKey).(*apis.RealtimeBridge) if ok { app.Logger().Info("Realtime bridge active", "channelId", bridge.SelfChannelId(), ) } return se.Next() }) ``` -------------------------------- ### Intercept Record Creation with OnRecordCreate Hook Source: https://context7.com/fondoger/pocketbase/llms.txt Automatically set the author from the authenticated user before saving a new record in the 'posts' collection. ```go app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error { // Auto-set the author from the authenticated user before saving if e.RequestInfo != nil && e.RequestInfo.Auth != nil { e.Record.Set("author", e.RequestInfo.Auth.Id) } return e.Next() // proceed with the save }) ``` -------------------------------- ### Execute Batch Requests Source: https://context7.com/fondoger/pocketbase/llms.txt Perform multiple record operations (create, update, delete, upsert) in a single, atomic transaction. Requires authentication. ```sh curl -X POST "http://127.0.0.1:8090/api/batch" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJ..." \ -d '{ "requests": [ { "method": "POST", "url": "/api/collections/posts/records", "body": { "title": "Post A", "status": "draft" } }, { "method": "PATCH", "url": "/api/collections/posts/records/abc123", "body": { "status": "published" } }, { "method": "DELETE", "url": "/api/collections/posts/records/old456" } ] }' # Response: array of individual responses in order # [ # { "status": 200, "body": { "id": "new789", "title": "Post A", ... } }, # { "status": 200, "body": { "id": "abc123", "status": "published", ... } }, # { "status": 204, "body": null } # ] ``` -------------------------------- ### Go: Custom Route Authentication Middleware Source: https://context7.com/fondoger/pocketbase/llms.txt Protect custom API routes using `apis.RequireAuth()`, `apis.RequireSuperuserAuth()`, or `apis.RequireGuestOnly()` middleware to control access based on authentication status. ```go app.OnServe().BindFunc(func(se *core.ServeEvent) error { // Allow only authenticated users from "users" or "members" collections se.Router.GET("/api/custom/dashboard", func(re *core.RequestEvent) error { userId := re.Auth.Id return re.JSON(http.StatusOK, map[string]string{"userId": userId}) }).Bind(apis.RequireAuth("users", "members")) // Allow only superusers se.Router.DELETE("/api/custom/purge", func(re *core.RequestEvent) error { return re.JSON(http.StatusOK, map[string]bool{"purged": true}) }).Bind(apis.RequireSuperuserAuth()) // Allow only guests (not authenticated) se.Router.POST("/api/custom/register", func(re *core.RequestEvent) error { return re.JSON(http.StatusOK, map[string]string{"status": "created"}) }).Bind(apis.RequireGuestOnly()) return se.Next() }) ``` -------------------------------- ### Create a New Record (REST API) Source: https://context7.com/fondoger/pocketbase/llms.txt Use `POST /api/collections/{collection}/records` to create a new record. Accepts JSON bodies for standard fields and `multipart/form-data` for file uploads. ```sh curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJ..." \ -d '{"title": "New Post", "status": "draft", "content": "Hello world"}' ``` ```sh curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \ -H "Authorization: Bearer eyJ..." \ -F "title=My Post with Image" \ -F "cover=@/path/to/image.jpg" ``` -------------------------------- ### Authenticate User with Password (REST API) Source: https://context7.com/fondoger/pocketbase/llms.txt Use `POST /api/collections/{collection}/auth-with-password` to authenticate a user with their identity (email/username) and password. Returns a JWT token and user record. ```sh curl -X POST "http://127.0.0.1:8090/api/collections/users/auth-with-password" \ -H "Content-Type: application/json" \ -d '{"identity": "user@example.com", "password": "MyPassword123"}' ``` -------------------------------- ### Database Transactions with app.RunInTransaction() Source: https://context7.com/fondoger/pocketbase/llms.txt Allows executing multiple database operations atomically. The hook system is fully active inside transactions, and operations are automatically rolled back on error. ```APIDOC ## Go API: `app.RunInTransaction()` — Database Transactions Execute multiple database operations atomically. The hook system is fully active inside transactions. ```go err := app.RunInTransaction(func(txApp core.App) error { col, err := txApp.FindCachedCollectionByNameOrId("orders") if err != nil { return err } order := core.NewRecord(col) order.Set("status", "pending") order.Set("total", 99.99) if err := txApp.Save(order); err != nil { return err // automatically rolls back } itemCol, err := txApp.FindCachedCollectionByNameOrId("order_items") if err != nil { return err } item := core.NewRecord(itemCol) item.Set("orderId", order.Id) item.Set("product", "Widget") item.Set("qty", 2) if err := txApp.Save(item); err != nil { return err // automatically rolls back both saves } return nil // commits both saves }) ``` ``` -------------------------------- ### Health Check Source: https://context7.com/fondoger/pocketbase/llms.txt Check if the PocketBase server is running. This endpoint provides basic health status and can offer additional diagnostics for superusers. ```sh # Public check curl "http://127.0.0.1:8090/api/health" # { "code": 200, "message": "API is healthy.", "data": {} } ``` -------------------------------- ### Scheduled Jobs (Cron) Source: https://context7.com/fondoger/pocketbase/llms.txt Schedule recurring background tasks using crontab syntax. ```APIDOC ## Scheduled Jobs with `app.Cron()` ### Description Allows scheduling recurring background tasks using standard crontab syntax. ### Usage Jobs are added using `app.Cron().MustAdd(jobName, cronExpression, taskFunction)`. ### Example Jobs #### Daily Cleanup - **Job Name**: `cleanupExpiredSessions` - **Cron Expression**: `0 0 * * *` (Runs daily at midnight UTC) - **Task**: Finds and deletes expired sessions. #### Heartbeat - **Job Name**: `heartbeat` - **Cron Expression**: `*/5 * * * *` (Runs every 5 minutes) - **Task**: Logs a heartbeat message. ``` -------------------------------- ### REST API: Create Record — POST /api/collections/{collection}/records Source: https://context7.com/fondoger/pocketbase/llms.txt Creates a new record within a specified collection. Accepts JSON bodies for standard fields and `multipart/form-data` for file uploads. ```APIDOC ## REST API: Create Record — `POST /api/collections/{collection}/records` Create a new record. File fields accept `multipart/form-data`. ```sh # JSON body curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJ..." \ -d '{"title": "New Post", "status": "draft", "content": "Hello world"}' # File upload (multipart) curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \ -H "Authorization: Bearer eyJ..." \ -F "title=My Post with Image" \ -F "cover=@/path/to/image.jpg" # Response: { "id": "xyz789", "title": "New Post", ... } ``` ``` -------------------------------- ### Request and Confirm Password Reset Source: https://context7.com/fondoger/pocketbase/llms.txt Two-step password reset process. First, request a reset email, then confirm the reset using the token from the email, along with the new password. ```sh # Step 1: request reset curl -X POST "http://127.0.0.1:8090/api/collections/users/request-password-reset" \ -H "Content-Type: application/json" \ -d '{"email": "user@example.com"}' # 204 No Content ``` ```sh # Step 2: confirm with token from email curl -X POST "http://127.0.0.1:8090/api/collections/users/confirm-password-reset" \ -H "Content-Type: application/json" \ -d '{"token": "reset_token_from_email", "password": "NewPass123", "passwordConfirm": "NewPass123"}' # 204 No Content ``` -------------------------------- ### Log All Record Update Requests Source: https://context7.com/fondoger/pocketbase/llms.txt Intercept HTTP-level record update events to log details about the collection and record ID being updated. ```go // Log all record update requests app.OnRecordUpdateRequest().BindFunc(func(e *core.RecordRequestEvent) error { app.Logger().Info("Record update requested", "collection", e.Collection.Name, "recordId", e.Record.Id, ) return e.Next() }) ```