Pocketbase
PocketBase single-binary BaaS with SQLite, auth, real-time, and file storage
You are an expert in PocketBase for rapid backend development, including its embedded SQLite database, authentication, real-time subscriptions, file storage, and Go extensibility.
## Key Points
- Use PocketBase's built-in admin UI to design collections and configure API rules during development, then export the schema for version control.
- Set API rules on every collection before deploying — leaving rules empty means no access (secure by default), but `null` rules mean open access.
- Use `expand` to resolve relations in a single API call rather than making multiple requests.
- For production, run PocketBase behind a reverse proxy (Caddy, Nginx) with TLS.
- Use the Go framework extension for custom business logic, webhooks, and background jobs instead of building a separate API.
- **Null vs. empty API rules**: A `null` (not set) rule means "no restriction" — completely open. An empty string `""` means "no access." Always explicitly set rules.
- **SQLite concurrency**: SQLite supports only one writer at a time; PocketBase serializes writes, so extremely high write throughput is not feasible.
- **File size limits**: Default max upload size is 5 MB; adjust `--maxRequestBodySize` flag or configure in the admin UI.
- **Backup strategy**: The database is a single SQLite file (`pb_data/data.db`); use `pb.backup()` or copy the file while the server is stopped for consistent backups.
- **Not using indexes**: For large collections, create indexes on fields you filter or sort by; PocketBase exposes index management in the admin UI.
## Quick Example
```bash
npm install pocketbase
```
```typescript
import PocketBase from 'pocketbase';
const pb = new PocketBase('http://127.0.0.1:8090');
```skilldb get baas-skills/PocketbaseFull skill: 280 linesPocketBase — Backend as a Service
You are an expert in PocketBase for rapid backend development, including its embedded SQLite database, authentication, real-time subscriptions, file storage, and Go extensibility.
Core Philosophy
Overview
PocketBase is an open-source backend consisting of a single binary. It embeds an SQLite database, provides a REST API with real-time subscriptions, user authentication (email/password and OAuth2), file storage, and an admin dashboard. It is written in Go and can be extended as a Go framework. PocketBase is ideal for small-to-medium projects, prototyping, and self-hosted applications.
Setup & Configuration
Installation
# Download the binary (Linux example)
wget https://github.com/pocketbase/pocketbase/releases/download/v0.22.0/pocketbase_0.22.0_linux_amd64.zip
unzip pocketbase_0.22.0_linux_amd64.zip
# Start the server
./pocketbase serve
# Admin dashboard: http://127.0.0.1:8090/_/
# API: http://127.0.0.1:8090/api/
JavaScript SDK
npm install pocketbase
import PocketBase from 'pocketbase';
const pb = new PocketBase('http://127.0.0.1:8090');
Docker
FROM alpine:latest
ADD https://github.com/pocketbase/pocketbase/releases/download/v0.22.0/pocketbase_0.22.0_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"]
Core Patterns
Authentication
// Sign up
const user = await pb.collection('users').create({
email: 'user@example.com',
password: 'secure-password',
passwordConfirm: 'secure-password',
name: 'Alice',
});
// Sign in with email/password
const authData = await pb.collection('users').authWithPassword(
'user@example.com',
'secure-password'
);
console.log(pb.authStore.token);
console.log(pb.authStore.model);
// OAuth2
const authData = await pb.collection('users').authWithOAuth2({ provider: 'github' });
// Check auth state
console.log(pb.authStore.isValid);
console.log(pb.authStore.model);
// Sign out
pb.authStore.clear();
// Listen to auth store changes
pb.authStore.onChange((token, model) => {
console.log('Auth changed:', token, model);
});
Database (Collections API)
// Create a record
const post = await pb.collection('posts').create({
title: 'My Post',
body: 'Content here',
author: pb.authStore.model.id,
published: true,
});
// Get a single record
const record = await pb.collection('posts').getOne(recordId);
// List with filters and pagination
const result = await pb.collection('posts').getList(1, 20, {
filter: 'published = true && created >= "2024-01-01"',
sort: '-created',
expand: 'author',
});
console.log(result.items);
console.log(result.totalItems);
// Get first matching record
const first = await pb.collection('posts').getFirstListItem(
`title ~ "search term"`
);
// Update a record
await pb.collection('posts').update(recordId, {
title: 'Updated Title',
});
// Delete a record
await pb.collection('posts').delete(recordId);
Filter Syntax
// PocketBase uses a custom filter syntax
const items = await pb.collection('posts').getFullList({
filter: `
published = true &&
author.name ~ "Alice" &&
created >= "2024-01-01 00:00:00" &&
tags ?~ "typescript"
`,
sort: '-created,title',
});
// Filter operators:
// = equal
// != not equal
// > greater than
// >= greater or equal
// < less than
// <= less or equal
// ~ like / contains
// !~ not like
// ?= any equal (for multi-valued fields)
// ?~ any like (for multi-valued fields)
Real-time Subscriptions
// Subscribe to changes in a collection
const unsubscribe = await pb.collection('posts').subscribe('*', (e) => {
console.log(e.action); // 'create', 'update', 'delete'
console.log(e.record);
});
// Subscribe to a specific record
const unsubscribe = await pb.collection('posts').subscribe(recordId, (e) => {
console.log('Record changed:', e.record);
});
// Unsubscribe
unsubscribe();
// Unsubscribe from all
pb.collection('posts').unsubscribe();
File Storage
// Upload files (via FormData or direct file)
const formData = new FormData();
formData.append('title', 'Post with Image');
formData.append('image', fileInput.files[0]);
const record = await pb.collection('posts').create(formData);
// Get file URL
const url = pb.files.getUrl(record, record.image, {
thumb: '100x100', // optional thumbnail
});
// Multiple files
formData.append('attachments', file1);
formData.append('attachments', file2);
Extending with 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()
// Add a custom route
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.GET("/api/hello", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{
"message": "Hello from custom endpoint!",
})
}, apis.ActivityLogger(app))
return nil
})
// Hook into record creation
app.OnRecordBeforeCreateRequest("posts").Add(func(e *core.RecordCreateEvent) error {
// Validate or modify the record before saving
e.Record.Set("slug", generateSlug(e.Record.GetString("title")))
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
Collection API Rules (Access Control)
Rules are set per collection in the admin UI or via the API. Each rule is a filter expression:
// List/Search rule — only published posts are visible
published = true || author = @request.auth.id
// Create rule — authenticated users only
@request.auth.id != ""
// Update rule — only the author
author = @request.auth.id
// Delete rule — only the author
author = @request.auth.id
Best Practices
- Use PocketBase's built-in admin UI to design collections and configure API rules during development, then export the schema for version control.
- Set API rules on every collection before deploying — leaving rules empty means no access (secure by default), but
nullrules mean open access. - Use
expandto resolve relations in a single API call rather than making multiple requests. - For production, run PocketBase behind a reverse proxy (Caddy, Nginx) with TLS.
- Use the Go framework extension for custom business logic, webhooks, and background jobs instead of building a separate API.
Common Pitfalls
- Null vs. empty API rules: A
null(not set) rule means "no restriction" — completely open. An empty string""means "no access." Always explicitly set rules. - SQLite concurrency: SQLite supports only one writer at a time; PocketBase serializes writes, so extremely high write throughput is not feasible.
- File size limits: Default max upload size is 5 MB; adjust
--maxRequestBodySizeflag or configure in the admin UI. - Backup strategy: The database is a single SQLite file (
pb_data/data.db); usepb.backup()or copy the file while the server is stopped for consistent backups. - Not using indexes: For large collections, create indexes on fields you filter or sort by; PocketBase exposes index management in the admin UI.
Anti-Patterns
Over-engineering for hypothetical requirements. Building for scenarios that may never materialize adds complexity without value. Solve the problem in front of you first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide wastes time and introduces risk.
Premature abstraction. Creating elaborate frameworks before having enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at system boundaries. Internal code can trust its inputs, but boundaries with external systems require defensive validation.
Skipping documentation. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add baas-skills
Related Skills
Appwrite
Appwrite self-hosted BaaS with database, auth, storage, and serverless functions
AWS Amplify
AWS Amplify BaaS with AppSync GraphQL, Cognito auth, S3 storage, and Lambda functions
Backendless
Backendless BaaS with real-time database, user authentication, Cloud Code,
Clerk Auth
Clerk authentication service with pre-built UI components, session management, and multi-framework support
Convex
Convex real-time backend with reactive queries, mutations, and serverless functions
Encore
Encore is a backend development platform that automatically provisions, configures, and manages cloud infrastructure based on your Go code. It simplifies building and deploying cloud-native applications by allowing you to focus purely on business logic.