Skill: PocketBase Schema
Tooling for authoring, inspecting, and validating PocketBase schema migrations. Use this skill during schema and feature work. For server lifecycle operations (init, dev, stop, reset), see the pocketbase skill.
Invocation: Use these operations whenever you need to create or modify PocketBase collections.
Prerequisites
- •PocketBase project already initialized (via
pocketbaseskill's PB Init) - •Go 1.23+ installed and on PATH
- •For Inspect: PocketBase server must be running (via
pb-dev.shorpb-reset.sh)
Operations
| Operation | Script | Description |
|---|---|---|
| Migrate Create | bash .github/skills/pocketbase-schema/pb-migrate-create.sh <description> [type] | Generate a timestamped migration file with boilerplate |
| Schema Inspect | bash .github/skills/pocketbase-schema/pb-schema-inspect.sh [collection-name] | Dump live schema as JSON (all collections or one) |
| Schema Validate | bash .github/skills/pocketbase-schema/pb-schema-validate.sh | Wipe data and dry-run all migrations to check for errors |
Migrate Create
Generates a new migration file in pb/pb_migrations/ with the correct timestamp and boilerplate.
# Create a new collection bash .github/skills/pocketbase-schema/pb-migrate-create.sh create_posts create # Modify an existing collection bash .github/skills/pocketbase-schema/pb-migrate-create.sh add_featured_to_posts modify # Seed data into a collection bash .github/skills/pocketbase-schema/pb-migrate-create.sh seed_categories seed
The type argument selects the boilerplate template:
- •
create(default):new Collection(...)skeleton with commented field examples - •
modify:findCollectionByNameOrId()skeleton with add/remove/modify examples - •
seed: Record insertion skeleton
After generating, edit the file to fill in collection name and fields.
Schema Inspect
Requires the server to be running.
# Dump all collections bash .github/skills/pocketbase-schema/pb-schema-inspect.sh # Dump a specific collection bash .github/skills/pocketbase-schema/pb-schema-inspect.sh posts
Schema Validate
Stops the server, wipes pb_data, and runs all migrations to check for errors. Does NOT restart the server — run pb-reset.sh or pb-dev.sh afterward.
bash .github/skills/pocketbase-schema/pb-schema-validate.sh
Workflow
Follow this loop when adding or modifying collections:
- •Inspect current schema to understand what exists
bash
bash .github/skills/pocketbase-schema/pb-schema-inspect.sh
- •Generate a migration boilerplate
bash
bash .github/skills/pocketbase-schema/pb-migrate-create.sh create_posts create
- •Edit the generated file — fill in collection name, fields, rules, and indexes
- •Validate — dry-run all migrations to catch errors
bash
bash .github/skills/pocketbase-schema/pb-schema-validate.sh
- •Reset & verify — start fresh server and check admin dashboard
bash
bash .github/skills/pocketbase/pb-reset.sh
Migration Authoring Rules
These rules prevent the most common agent mistakes. Follow them strictly.
Relations: Always Look Up Collection IDs
Never hardcode a collectionId. Always resolve it at migration time:
migrate((app) => {
const users = app.findCollectionByNameOrId("users")
const collection = new Collection({
name: "posts",
type: "base",
fields: [
new RelationField({
name: "author",
collectionId: users.id, // CORRECT: resolved at runtime
maxSelect: 1,
cascadeDelete: false,
}),
],
})
app.save(collection)
})
Migration Ordering
- •Files run in filename order (lexicographic by timestamp prefix)
- •A migration that references another collection must come after the migration that creates it
- •Use
pb-migrate-create.shto get correct timestamps — do NOT manually set timestamps
Always Write DOWN Migrations
Every migrate() call takes two callbacks: UP and DOWN. Always implement both:
migrate((app) => {
// UP: create or modify
}, (app) => {
// DOWN: reverse the UP changes
})
Auth Collections
Auth collections get system fields automatically (email, emailVisibility, verified, password, tokenKey). Do not re-declare them. Only add your custom fields:
const collection = new Collection({
type: "auth",
name: "users",
fields: [
new TextField({ name: "displayName", max: 100 }),
// email, password, etc. are added automatically
],
passwordAuth: { enabled: true },
})
View Collections
View collections are read-only and backed by a SQL SELECT:
const collection = new Collection({
type: "view",
name: "posts_with_authors",
viewQuery: "SELECT p.id, p.title, u.displayName as author FROM posts p JOIN users u ON p.author = u.id",
// listRule / viewRule apply; create/update/delete rules are ignored
})
Common Mistakes
| Mistake | Fix |
|---|---|
Hardcoded collectionId: "abc123" | Use app.findCollectionByNameOrId("name").id |
| Migration references a collection that doesn't exist yet | Ensure the creating migration has an earlier timestamp |
Re-declaring email, password on auth collections | These are system fields — they exist automatically |
| Missing DOWN migration | Always implement the second callback to migrate() |
Using $app instead of app | The callback parameter is app, not $app |
Setting rules to undefined or omitting them | Use null (superuser only), "" (public), or a filter string |
new Field(...) instead of new TextField(...) | Use the specific constructor: TextField, NumberField, etc. |
| Manually naming migration files | Always use pb-migrate-create.sh for correct timestamps |
Field Types Quick Reference
| Constructor | Key Options |
|---|---|
TextField | required, min, max, pattern |
NumberField | required, min, max, onlyInt |
BoolField | required |
EmailField | required, onlyDomains, exceptDomains |
URLField | required, onlyDomains, exceptDomains |
DateField | required |
AutodateField | onCreate, onUpdate |
SelectField | values (required), maxSelect |
FileField | maxSelect, maxSize, mimeTypes, thumbs, protected |
RelationField | collectionId (required), maxSelect, cascadeDelete |
JSONField | required (nullable unlike other fields) |
EditorField | required, maxSize, convertURLs |
PasswordField | required, min, max, cost |
GeoPointField | required |
API Rules Quick Reference
| Value | Meaning |
|---|---|
null | Superuser only (locked) |
"" | Public access (no auth required) |
"@request.auth.id != ''" | Any authenticated user |
"author = @request.auth.id" | Owner only |
"@request.auth.verified = true" | Verified users only |
Rules support: =, !=, >, >=, <, <=, ~ (contains), !~, &&, ||
For multi-value relation checks use ?=: "members ?= @request.auth.id"
For the full JS Migration API reference, see the pocketbase skill's JS Migration Reference section.