Pocketbase | Skills Pool
Pocketbase Open-source SQLite backend with realtime subscriptions. Use for rapid prototyping.
NOT for large-scale multi-tenant applications needing PostgreSQL.
Single-file backend: SQLite + realtime + auth + file storage. Deploy as binary or Docker.
Quick Start
# Download binary
curl -L https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip -o pb.zip
unzip pb.zip && chmod +x pocketbase
# Start server
./pocketbase serve
# Admin UI: http://127.0.0.1:8090/_/ (create first admin)
# API: http://127.0.0.1:8090/api/
Core Concepts
Feature Description Collections Tables (SQLite) with auto-generated REST API Records Rows with typed fields + metadata Auth Built-in email/password, OAuth2, JWT tokens Realtime SSE subscriptions to record changes
npx skillvault add srijan-at-qwertystars/srijan-at-qwertystars-skillforge-backend-pocketbase-skill-md
星標 0
更新時間 2026年3月29日
職業 File uploads with S3-compatible backend
Rules Access control via Go-like expressions
Collections
Create via Admin UI
Go to /_/collections
Click "Create new collection"
Define fields:
name (text, required)
email (email, unique)
avatar (file, single)
status (select: active|inactive)
metadata (json)
API Schema GET /api/collections/posts/records
POST /api/collections/posts/records
PATCH /api/collections/posts/records/:id
DELETE /api/collections/posts/records/:id
JavaScript SDK import PocketBase from 'pocketbase';
const pb = new PocketBase('http://127.0.0.1:8090');
// Auth
await pb.collection('users').authWithPassword('[email protected] ', 'password123');
console.log(pb.authStore.token); // JWT
// CRUD
const record = await pb.collection('posts').create({
title: 'Hello World',
content: 'Body text',
author: pb.authStore.model?.id
});
const records = await pb.collection('posts').getList(1, 20, {
filter: 'status = "published"',
sort: '-created',
expand: 'author'
});
// Update
await pb.collection('posts').update(record.id, { title: 'Updated' });
// Delete
await pb.collection('posts').delete(record.id);
Realtime Subscriptions // Subscribe to all changes
pb.collection('posts').subscribe('*', (e) => {
console.log(e.action, e.record); // create, update, delete
});
// Subscribe to specific record
pb.collection('posts').subscribe('RECORD_ID', (e) => {
console.log('Record changed:', e.record);
});
// Filtered subscription
pb.collection('posts').subscribe('*', (e) => {
if (e.record.author === currentUserId) {
console.log('My post changed');
}
});
// Unsubscribe
pb.collection('posts').unsubscribe(); // all
pb.collection('posts').unsubscribe('RECORD_ID'); // specific
File Handling // Upload
const formData = new FormData();
formData.append('title', 'My Post');
formData.append('attachment', fileInput.files[0]);
const record = await pb.collection('posts').create(formData);
// Get file URL
const url = pb.files.getUrl(record, record.attachment);
// Output: http://127.0.0.1:8090/api/files/posts/RECORD_ID/filename.jpg
// Download with auth
const fileUrl = pb.files.getUrl(record, record.attachment, { token: pb.authStore.token });
Go SDK (Custom Routes) package main
import (
"log"
"net/http"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
// Custom route
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.GET("/api/hello", func(c echo.Context) error {
return c.JSON(200, map[string]string{"message": "Hello"})
})
return nil
})
// Hook: before create
app.OnRecordBeforeCreateRequest("posts").Add(func(e *core.RecordCreateEvent) error {
// Auto-set slug from title
title := e.Record.GetString("title")
e.Record.Set("slug", slug.Make(title))
return nil
})
// Hook: after create - send notification
app.OnRecordAfterCreateRequest("posts").Add(func(e *core.RecordCreateEvent) error {
go sendNotification(e.Record.GetString("author"))
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
Go: Direct Database Access // Raw SQL
results, err := app.Dao().DB().NewQuery(`
SELECT * FROM posts WHERE status = 'published' ORDER BY created DESC
`).Execute()
// Using DAO
posts, err := app.Dao().FindRecordsByFilter("posts", "status = 'published'", "-created", 10, 0)
// Transaction
err := app.Dao().RunInTransaction(func(txDao *daos.Dao) error {
record := models.NewRecord(collection)
record.Set("title", "Transaction Test")
return txDao.SaveRecord(record)
})
Access Rules Rules use Go-like syntax. Available variables: @request.*, @collection.*
Collection-Level Rules List/Search Rule: @request.auth.id != "" && status = "published"
View Rule: status = "published" || author = @request.auth.id
Create Rule: @request.auth.id != ""
Update Rule: author = @request.auth.id
Delete Rule: author = @request.auth.id || @request.auth.role = "admin"
Field-Level Rules // Only author can see draft content
@request.auth.id = author || status = "published"
// Email only visible to owner
@request.auth.id = id
// Admin-only field
@request.auth.role = "admin"
Common Patterns # User owns record
author = @request.auth.id
# Public read, auth write
List: true
Create: @request.auth.id != ""
# Team-based access
@request.auth.id ?= members.id
# Time-based (published posts)
status = "published" && published <= @now
Auth Providers
Email/Password // Register
await pb.collection('users').create({
email: '[email protected] ',
password: 'securepass123',
passwordConfirm: 'securepass123',
name: 'John Doe'
});
// Login
await pb.collection('users').authWithPassword('[email protected] ', 'securepass123');
// OAuth2
await pb.collection('users').authWithOAuth2({ provider: 'google' });
Custom Auth Collection // Create "vendors" collection with "Authenticate" option enabled
await pb.collection('vendors').authWithPassword('[email protected] ', 'pass123');
Self-Hosting
Binary ./pocketbase serve --http="0.0.0.0:8090" --dir="./pb_data"
Docker FROM ghcr.io/m/pocketbase:latest
EXPOSE 8090
CMD ["serve", "--http=0.0.0.0:8090"]
02
Core Concepts