Agent skill
pocketbase-migrations
Comprehensive guide for PocketBase migrations (0.20+) using Go-based migration system. Use when creating or modifying PocketBase collections, managing fields, setting up relations, or writing migration files.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/pocketbase-migrations
SKILL.md
PocketBase Migrations
Guide for creating PocketBase migrations using the Go-based system (0.20+).
Core Workflow
Critical Migration Pattern
ALWAYS follow this workflow:
- Write ONE migration at a time
- Execute immediately with
mise run migrate - Verify it worked with
mise run show-collections - Only then write the next migration
- Run
mise run backupbefore destructive changes
Never write multiple migrations without running them between each one.
Migration Structure
go
package migrations
import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/types"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
// Up migration
return nil
}, func(app core.App) error {
// Down migration
return nil
})
}
Collection Operations
Create Base Collection
go
collection := core.NewBaseCollection("posts")
// Add fields
collection.Fields.Add(&core.TextField{
Name: "title",
Required: true,
Max: 100,
})
// Set rules (use types.Pointer())
collection.ListRule = types.Pointer("@request.auth.id != ''")
collection.CreateRule = types.Pointer("@request.auth.id != ''")
collection.UpdateRule = types.Pointer("@request.auth.id = author")
collection.DeleteRule = types.Pointer("@request.auth.id = author")
return app.Save(collection)
Update Existing Collection
go
collection, err := app.FindCollectionByNameOrId("posts")
if err != nil {
return err
}
// Add field
collection.Fields.Add(&core.DateField{
Name: "publishedAt",
})
// Remove field
collection.Fields.RemoveByName("oldField")
// Update rules
collection.UpdateRule = types.Pointer("@request.auth.id = author")
return app.Save(collection)
Common Field Types
See references/field-types.md for complete field type reference.
Quick Reference
go
// Text
&core.TextField{Name: "title", Required: true, Max: 100}
// Number
&core.NumberField{Name: "price", Min: types.Pointer(0.0)}
// Boolean
&core.BoolField{Name: "isActive"}
// Email
&core.EmailField{Name: "email", Required: true}
// Date
&core.DateField{Name: "publishedAt"}
// Auto-managed date
&core.AutodateField{Name: "created", OnCreate: true}
// Select
&core.SelectField{
Name: "status",
Values: []string{"draft", "published"},
MaxSelect: 1,
}
// File
&core.FileField{
Name: "avatar",
MaxSelect: 1,
MaxSize: 5242880, // bytes
}
// Editor (rich text)
&core.EditorField{
Name: "content",
MaxSize: 1048576,
}
// JSON
&core.JSONField{Name: "metadata", MaxSize: 65535}
Working with Relations
Best Practices
- Create collections in dependency order
- Fetch collections before creating relations
- Use actual collection IDs for relations
- Handle self-referencing relations in separate migrations
Relation Field
go
// Fetch the target collection first
authorsCollection, err := app.FindCollectionByNameOrId("authors")
if err != nil {
return err
}
// Add relation field
collection.Fields.Add(&core.RelationField{
Name: "author",
Required: true,
MaxSelect: 1, // Note: use MaxSelect, not Max
CollectionId: authorsCollection.Id,
CascadeDelete: true,
})
// System users collection
collection.Fields.Add(&core.RelationField{
Name: "creator",
CollectionId: "_pb_users_auth_",
MaxSelect: 1,
})
Migration Order for Relations
Create collections in this order:
- Independent collections (no relations)
- Collections depending on system collections
- Collections with relations to other custom collections
- Self-referencing relations (separate migration)
Example order:
1_create_categories.go # Independent
2_create_authors.go # Depends on system users
3_create_posts.go # Depends on authors & categories
4_create_comments.go # Depends on posts & users
5_add_parent_to_comments.go # Self-referencing
Collection Rules
Rule Types
ListRule- List recordsViewRule- View individual recordsCreateRule- Create recordsUpdateRule- Update recordsDeleteRule- Delete records
Common Patterns
go
// Public access
types.Pointer("")
// Authenticated only
types.Pointer("@request.auth.id != ''")
// Owner only
types.Pointer("@request.auth.id = author")
// Published or owner
types.Pointer("status = 'published' || author = @request.auth.id")
// Through relations
types.Pointer("author.user = @request.auth.id")
View Collections
go
viewQuery := `
SELECT
posts.id,
posts.title,
users.name as author_name
FROM posts
JOIN users ON posts.author = users.id
`
collection := core.NewViewCollection("posts_with_authors", viewQuery)
return app.Save(collection)
Error Handling
Always check errors:
go
collection, err := app.FindCollectionByNameOrId("posts")
if err != nil {
return err
}
if err := app.Save(collection); err != nil {
return err
}
Task Commands
mise run makemigration <name>- Create new migration filemise run migrate- Run pending migrationsmise run migratedown- Rollback last migrationmise run show-collections- Display collectionsmise run backup- Backup database to /tmp
Best Practices
- Import types package for nullable values:
"github.com/pocketbase/pocketbase/tools/types" - Use
types.Pointer()for rule assignments and pointer values - Check collection existence before creating relations
- Validate field names don't conflict with system fields (id, created, updated)
- Handle errors immediately after operations
- Never skip migration testing - run each one before writing the next
- Backup before destructive changes
Common Gotchas
- Use
MaxSelect(notMax) for RelationField - Use
MaxSize(notMax) for EditorField - System users collection ID:
"_pb_users_auth_" - For number min/max:
types.Pointer(0.0) - Empty rules need:
types.Pointer("") - Self-referencing relations need separate migrations
Additional Resources
- Field types reference: references/field-types.md
- Official docs: https://pocketbase.io/docs/go-collections/
Didn't find tool you were looking for?