PocketBase: Self-Hosted Backend in a Single File
PocketBase packs a complete backend — SQLite database, real-time subscriptions, authentication, file storage, and an admin UI — into a single executable file. It's the shortest path from "I need a backend" to something actually running.
Photo by BoliviaInteligente on Unsplash
If you've used Firebase or Supabase but want to self-host without the complexity, PocketBase is worth a close look.
What PocketBase Gives You
A single pocketbase binary provides:
- SQLite database with automatic migrations and admin UI
- REST API generated from your schema with zero configuration
- Real-time subscriptions via Server-Sent Events
- Authentication — email/password, OAuth2, and anonymous users
- File storage — local disk or S3-compatible storage
- Hooks and custom routes in JavaScript or Go
The admin dashboard is built in and available immediately after starting.
Getting Started
Download the appropriate binary from GitHub releases:
# Linux AMD64
curl -L https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip -o pocketbase.zip
unzip pocketbase.zip
chmod +x pocketbase
# Start the server
./pocketbase serve
Navigate to http://localhost:8090/_/ to access the admin UI and create your first admin account.
Docker Setup
For a persistent deployment with Docker:
services:
pocketbase:
image: ghcr.io/muchobien/pocketbase:latest
container_name: pocketbase
ports:
- "8090:8090"
volumes:
- pb_data:/pb/pb_data
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8090/api/health"]
interval: 10s
timeout: 5s
retries: 3
volumes:
pb_data:
Creating Your Data Model
In the admin UI under Collections, create collections (think: database tables):
- Click New collection
- Name it (e.g.,
posts) - Add fields: text, number, email, date, select, file, relation, etc.
- Set API rules to control who can read/write
PocketBase generates the full REST API immediately — no code needed.
Example: Blog Posts Collection
| Field | Type | Required |
|---|---|---|
| title | Text | ✓ |
| content | Editor | ✓ |
| published | Bool | |
| author | Relation (users) | ✓ |
| cover | File |
This collection automatically gets:
GET /api/collections/posts/records— listPOST /api/collections/posts/records— createGET /api/collections/posts/records/:id— viewPATCH /api/collections/posts/records/:id— updateDELETE /api/collections/posts/records/:id— delete
Authentication
PocketBase has a built-in _pb_users_auth_ collection. To authenticate:
import PocketBase from 'pocketbase';
const pb = new PocketBase('http://localhost:8090');
// Login
const authData = await pb.collection('users').authWithPassword(
'[email protected]',
'password123'
);
// The client automatically stores the token and refreshes it
console.log(pb.authStore.isValid); // true
console.log(pb.authStore.model); // user record
OAuth2 works similarly — just add providers (Google, GitHub, Discord, etc.) in the admin UI and call authWithOAuth2().
Real-Time Subscriptions
This is where PocketBase stands out from simple REST APIs:
// Subscribe to all changes in the 'posts' collection
pb.collection('posts').subscribe('*', function(e) {
console.log(e.action); // create, update, delete
console.log(e.record); // the changed record
});
// Subscribe to a single record
pb.collection('posts').subscribe('RECORD_ID', function(e) {
console.log('Post updated:', e.record.title);
});
// Unsubscribe
pb.collection('posts').unsubscribe();
This works without WebSockets — PocketBase uses Server-Sent Events under the hood.
Extending with JavaScript Hooks
PocketBase has a JavaScript runtime (based on goja) for server-side logic:
// pb_hooks/main.pb.js
// Run before creating a post
onRecordBeforeCreateRequest((e) => {
const record = e.record;
// Validate slug uniqueness
if (!record.get("slug")) {
const title = record.get("title");
record.set("slug", title.toLowerCase().replace(/\s+/g, "-"));
}
return e.next();
}, "posts");
// Custom API endpoint
routerAdd("GET", "/api/stats", (c) => {
const count = $app.dao().findRecordsByFilter("posts", "published = true", "", 0, 0).length;
return c.json(200, { published: count });
});
Hooks support onRecordBefore/AfterCreate/Update/Delete, mail hooks, and more.
File Storage
By default, files are stored locally in pb_data/storage. For S3:
In the admin UI → Settings → Files storage, configure:
- S3 endpoint, region, bucket
- Access key and secret
Or pass at startup:
./pocketbase serve \
--s3Endpoint=https://s3.amazonaws.com \
--s3Region=us-east-1 \
--s3Bucket=my-pb-files \
--s3AccessKey=AKIAIOSFODNN7EXAMPLE \
--s3Secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
API Rules
Control access with rule strings. They use a filter syntax:
| Rule | Meaning |
|---|---|
"" (empty) |
Locked — no one can access |
@request.auth.id != "" |
Any authenticated user |
@request.auth.id = author |
Only the record's author |
admin = @request.auth.id |
Custom admin field check |
Set these per collection and per operation (list, view, create, update, delete).
Comparison: PocketBase vs Alternatives
| Feature | PocketBase | Supabase | Appwrite | Firebase |
|---|---|---|---|---|
| Self-hostable | ✓ | ✓ | ✓ | ✗ |
| Deployment complexity | Single binary | Docker Compose (many containers) | Docker Compose | Managed |
| Database | SQLite | PostgreSQL | MariaDB | NoSQL |
| Real-time | SSE | WebSockets | WebSockets | WebSockets |
| Free tier | Unlimited (self-hosted) | Generous | Generous | Limited |
PocketBase's single-binary deployment is its killer feature. Supabase is more powerful for complex SQL needs; PocketBase wins for simple, fast deployments.
Production Considerations
Backups: SQLite databases are easy to back up — just copy pb_data/data.db:
# Daily backup cron
0 2 * * * sqlite3 /path/to/pb_data/data.db ".backup '/backups/pocketbase-$(date +%Y%m%d).db'"
Performance: SQLite handles thousands of requests per second for most apps. For write-heavy workloads with concurrent writers, consider whether PostgreSQL (via Supabase or Directus) is more appropriate.
Scaling: PocketBase is single-instance. If you need horizontal scaling, it's not the right tool. For most projects, vertical scaling (a bigger VM) gets you very far.
When to Use PocketBase
PocketBase is excellent for:
- Personal projects and side projects
- Small SaaS products with moderate traffic
- Prototypes you want to ship quickly
- Apps where the backend complexity doesn't need to justify Kubernetes
Skip it for: multi-region deployments, write-heavy apps expecting PostgreSQL semantics, or anywhere you need high-availability replication.
