PocketBase Cheat Sheet
Overview
PocketBase is an open-source backend that packages a SQLite database, realtime subscriptions, built-in authentication, file storage, and an admin dashboard into a single portable binary. It is written in Go and requires zero external dependencies, making it ideal for prototyping, small to medium applications, and self-hosted projects.
PocketBase provides a REST API automatically for all your collections (database tables), supports OAuth2 authentication with multiple providers, offers realtime events via Server-Sent Events, and includes an extensible Go and JavaScript SDK. The admin UI lets you manage collections, records, users, and settings through a browser-based interface.
Installation
# Download the latest release (Linux AMD64)
curl -Lo pocketbase.zip https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_0.25.0_linux_amd64.zip
unzip pocketbase.zip
chmod +x pocketbase
# macOS (ARM64)
curl -Lo pocketbase.zip https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_0.25.0_darwin_arm64.zip
unzip pocketbase.zip
# Start the server
./pocketbase serve
# Start on a specific address and port
./pocketbase serve --http="0.0.0.0:8090"
# Admin UI: http://127.0.0.1:8090/_/
# API: http://127.0.0.1:8090/api/
Docker
FROM alpine:latest
ARG PB_VERSION=0.25.0
RUN apk add --no-cache unzip ca-certificates
ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip
RUN unzip /tmp/pb.zip -d /pb/
EXPOSE 8090
CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8090"]
docker build -t pocketbase .
docker run -p 8090:8090 -v $(pwd)/pb_data:/pb/pb_data pocketbase
Core API
Collections (CRUD)
| Method | Endpoint | Description |
|---|---|---|
GET | /api/collections/{collection}/records | List records |
GET | /api/collections/{collection}/records/{id} | Get one record |
POST | /api/collections/{collection}/records | Create a record |
PATCH | /api/collections/{collection}/records/{id} | Update a record |
DELETE | /api/collections/{collection}/records/{id} | Delete a record |
Example API Calls
# List records with filtering
curl "http://127.0.0.1:8090/api/collections/posts/records?filter=(status='published')&sort=-created&perPage=20" \
-H "Authorization: Bearer USER_TOKEN"
# Create a record
curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer USER_TOKEN" \
-d '{"title":"Hello","content":"World","status":"draft"}'
# Update a record
curl -X PATCH "http://127.0.0.1:8090/api/collections/posts/records/RECORD_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer USER_TOKEN" \
-d '{"status":"published"}'
# Delete a record
curl -X DELETE "http://127.0.0.1:8090/api/collections/posts/records/RECORD_ID" \
-H "Authorization: Bearer USER_TOKEN"
# Upload a file
curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \
-H "Authorization: Bearer USER_TOKEN" \
-F "title=My Post" \
-F "image=@photo.jpg"
Authentication
# Register a new user
curl -X POST "http://127.0.0.1:8090/api/collections/users/records" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"securepass123","passwordConfirm":"securepass123","name":"Alice"}'
# Authenticate (get token)
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":"securepass123"}'
# OAuth2 authentication
curl -X POST "http://127.0.0.1:8090/api/collections/users/auth-with-oauth2" \
-H "Content-Type: application/json" \
-d '{"provider":"google","code":"AUTH_CODE","redirectURL":"http://localhost:3000/auth/callback"}'
Filtering and Sorting
# Filter syntax
filter=(status='published' && created>'2025-01-01')
filter=(title~'hello' || tags?~'news')
filter=(author.name='Alice')
# Sort (prefix with - for descending)
sort=-created,title
# Field selection
fields=id,title,created
# Expand relations
expand=author,comments
JavaScript SDK
import PocketBase from "pocketbase"
const pb = new PocketBase("http://127.0.0.1:8090")
// Authenticate
const authData = await pb.collection("users").authWithPassword("user@example.com", "securepass123")
// List records
const posts = await pb.collection("posts").getList(1, 20, {
filter: 'status = "published"',
sort: "-created",
expand: "author",
})
// Get one record
const post = await pb.collection("posts").getOne("RECORD_ID", {
expand: "author,comments",
})
// Create a record
const newPost = await pb.collection("posts").create({
title: "New Post",
content: "Hello World",
author: pb.authStore.record.id,
})
// Update a record
await pb.collection("posts").update("RECORD_ID", { status: "published" })
// Delete a record
await pb.collection("posts").delete("RECORD_ID")
// Realtime subscriptions
pb.collection("posts").subscribe("*", function (e) {
console.log(e.action) // create, update, delete
console.log(e.record)
})
// Unsubscribe
pb.collection("posts").unsubscribe()
Configuration
Collection Schema (via Admin UI or API)
{
"name": "posts",
"type": "base",
"schema": [
{ "name": "title", "type": "text", "required": true, "options": { "min": 1, "max": 200 } },
{ "name": "content", "type": "editor", "required": false },
{ "name": "status", "type": "select", "options": { "values": ["draft", "published", "archived"] } },
{ "name": "image", "type": "file", "options": { "maxSelect": 1, "maxSize": 5242880, "mimeTypes": ["image/png", "image/jpeg"] } },
{ "name": "author", "type": "relation", "options": { "collectionId": "users", "maxSelect": 1 } },
{ "name": "tags", "type": "json" }
]
}
API Rules (Access Control)
# In Admin UI > Collection > API Rules
# List rule (who can list records)
@request.auth.id != "" && status = "published"
# View rule
@request.auth.id != "" || status = "published"
# Create rule
@request.auth.id != "" && @request.data.author = @request.auth.id
# Update rule
@request.auth.id = author.id
# Delete rule
@request.auth.id = author.id
Advanced Usage
Custom Go Backend
package main
import (
"log"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
app.OnRecordCreate("posts").BindFunc(func(e *core.RecordEvent) error {
log.Println("New post created:", e.Record.GetString("title"))
return e.Next()
})
app.OnServe().BindFunc(func(se *core.ServeEvent) error {
se.Router.GET("/api/custom/hello", func(e *core.RequestEvent) error {
return e.JSON(200, map[string]string{"message": "Hello!"})
})
return se.Next()
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
Migrations
# Create a migration
./pocketbase migrate create "add_posts_collection"
# Run migrations
./pocketbase migrate up
# Rollback
./pocketbase migrate down
Backup and Restore
# Create a backup via API
curl -X POST "http://127.0.0.1:8090/api/backups" \
-H "Authorization: Bearer ADMIN_TOKEN"
# List backups
curl "http://127.0.0.1:8090/api/backups" \
-H "Authorization: Bearer ADMIN_TOKEN"
# Manual backup: just copy the pb_data directory
cp -r pb_data pb_data_backup_$(date +%Y%m%d)
Troubleshooting
| Issue | Solution |
|---|---|
| Admin UI not loading | Ensure you are accessing /_/ path; check firewall rules |
| Auth token expired | Tokens expire after 14 days by default; re-authenticate |
| File upload fails | Check maxSize in schema; verify pb_data/storage has write permissions |
| Realtime not connecting | Ensure client uses SSE-compatible connection; check CORS settings |
| Database locked | SQLite allows one writer at a time; use WAL mode (default) for better concurrency |
| Relations not expanding | Use expand=relation_field query param; verify relation field name |
| CORS errors | Configure allowed origins in Admin UI > Settings > Application |
| Slow queries | Add indexes via Admin UI; reduce perPage size; filter on indexed fields |