Pb Migrations Studio
Production-ready skill that handles schema, migrations, versioning, pocketbase. Includes structured workflows, validation checks, and reusable patterns for pocketbase.
PB Migrations Studio
A comprehensive skill for PocketBase schema migrations — covering auto-generated migrations, manual migration writing, schema versioning, data migrations, rollback strategies, and migration best practices for PocketBase applications.
When to Use This Skill
Choose PB Migrations Studio when you need to:
- Manage PocketBase schema changes with version-controlled migrations
- Write manual migrations for complex schema transformations
- Perform data migrations alongside schema changes
- Set up a migration workflow for team development
- Roll back schema changes when deployments go wrong
Consider alternatives when:
- You need collection schema design (use a PB collections skill)
- You need server-side hooks (use a PB hooks skill)
- You need general database migrations (use a DB migration skill)
Quick Start
# PocketBase auto-generates migrations when using Admin UI # Files appear in: pb_migrations/ # Manual migration creation touch pb_migrations/1734567890_create_posts.js
// pb_migrations/1734567890_create_posts.js migrate( // Up — apply migration function(db) { var collection = new Collection({ name: "posts", type: "base", schema: [ { name: "title", type: "text", required: true }, { name: "content", type: "editor" }, { name: "author", type: "relation", options: { collectionId: "USERS_COLLECTION_ID", maxSelect: 1, }}, { name: "status", type: "select", options: { values: ["draft", "published", "archived"], }}, { name: "published_at", type: "date" }, ], listRule: "status = 'published' || author = @request.auth.id", viewRule: "status = 'published' || author = @request.auth.id", createRule: "@request.auth.id != ''", updateRule: "author = @request.auth.id", deleteRule: "author = @request.auth.id", }); return Dao(db).saveCollection(collection); }, // Down — rollback migration function(db) { var collection = Dao(db).findCollectionByNameOrId("posts"); return Dao(db).deleteCollection(collection); } );
Core Concepts
Migration Approaches
| Approach | When to Use | How It Works |
|---|---|---|
| Auto-migrate | Development, prototyping | Admin UI changes → auto files |
| Manual migrate | Production, team workflows | Hand-written migration files |
| Hybrid | Most projects | Auto in dev, manual for prod |
Migration File Structure
## File Naming Convention {unix_timestamp}_{description}.js Examples: - 1734567890_create_posts.js - 1734567891_add_slug_to_posts.js - 1734567892_create_comments.js - 1734567893_add_index_on_posts_slug.js ## Execution Order Migrations run in alphabetical/timestamp order. Always use timestamps to ensure correct ordering.
Common Migration Operations
// Add a field to existing collection migrate(function(db) { var dao = new Dao(db); var collection = dao.findCollectionByNameOrId("posts"); collection.schema.addField(new SchemaField({ name: "slug", type: "text", required: true, options: { maxLength: 200 }, })); // Add unique index collection.indexes = collection.indexes || []; collection.indexes.push("CREATE UNIQUE INDEX idx_posts_slug ON posts (slug)"); return dao.saveCollection(collection); }, function(db) { var dao = new Dao(db); var collection = dao.findCollectionByNameOrId("posts"); collection.schema.removeField("slug"); return dao.saveCollection(collection); }); // Rename a field migrate(function(db) { var dao = new Dao(db); var collection = dao.findCollectionByNameOrId("posts"); var field = collection.schema.getFieldByName("body"); field.name = "content"; return dao.saveCollection(collection); }, function(db) { var dao = new Dao(db); var collection = dao.findCollectionByNameOrId("posts"); var field = collection.schema.getFieldByName("content"); field.name = "body"; return dao.saveCollection(collection); }); // Data migration migrate(function(db) { var dao = new Dao(db); var records = dao.findRecordsByFilter("posts", "slug = ''", "", 0, 0); for (var i = 0; i < records.length; i++) { var title = records[i].get("title"); var slug = title.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""); records[i].set("slug", slug); dao.saveRecord(records[i]); } });
Configuration
| Parameter | Description | Example |
|---|---|---|
migrations_dir | Directory for migration files | "pb_migrations/" |
auto_migrate | Enable auto-migration from Admin UI | true (dev) / false (prod) |
naming_format | Migration file naming convention | "{timestamp}_{description}" |
Best Practices
-
Always write both up and down migrations — Every migration should be reversible. If you add a field, the down migration removes it. If you change data, the down migration restores it. Skipping down migrations makes rollbacks impossible when deployments fail.
-
Use auto-migrate in development, manual migrations for production — Auto-migration is convenient for prototyping but generates verbose, hard-to-read files. For production deployments, write clean manual migrations that are reviewable and testable.
-
Never modify a migration that's already been applied — Once a migration runs on any environment (staging, production), it's immutable. Create a new migration to fix issues. Modifying applied migrations causes state mismatches between environments.
-
Test migrations on a copy of production data — Before applying migrations to production, restore a production backup to a test environment and run the migration there. Schema changes that work on empty databases can fail on production data with edge cases.
-
Include data migrations when changing field types or constraints — If you change a text field to a select field, existing records may contain values that aren't in the select options. Write a data migration that transforms existing values before changing the schema.
Common Issues
Auto-generated migrations conflict between team members — Two developers making schema changes simultaneously generate migrations with different timestamps that may conflict. Coordinate schema changes through a single branch, or use manual migrations that can be reviewed in pull requests.
Migration fails on production but worked in development — Production databases have data; development databases are often empty. A migration that adds a required field fails on production because existing records don't have values for it. Always add new required fields with a default value or make them optional initially.
Rollback removes data permanently — Dropping a column in a down migration deletes all data in that column irreversibly. For critical fields, down migrations should rename the column (e.g., _old_slug) instead of dropping it, allowing data recovery if needed.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.