AGENT SKILL

pb-migrations

Schema migrations and versioning for PocketBase. Use when creating migrations, managing schema versions, syncing collections between environments, using automigrate, or creating collections programmatically. Covers migrate commands, migration file format, snapshot imports, and the _migrations tracking table.

License 许可
MIT
最近更新
2026-11-11
Stars
★ 3.3w
Forks
3.9k

01 前言 Front Matter

name
pb-migrations
description
Schema migrations and versioning for PocketBase. Use when creating migrations, managing schema versions, syncing collections between environments, using automigrate, or creating collections programmatically. Covers migrate commands, migration file format, snapshot imports, and the _migrations tracking table.

03 SKILL.md 正文

PocketBase Migrations & Schema Versioning

Overview

PocketBase supports two approaches to schema management:

  1. Auto-migrate (default in dev) — Dashboard changes auto-generate migration files in pb_migrations/
  2. Manual migrations — write migration files by hand for full control

CLI Commands

# Create a new empty migration file
./pocketbase migrate create "add_posts_collection"
# Creates: pb_migrations/1234567890_add_posts_collection.js

# Apply all pending migrations
./pocketbase migrate up

# Revert the last applied migration
./pocketbase migrate down

# Generate a full snapshot of all current collections
./pocketbase migrate collections
# Creates a migration file that recreates all collections from scratch

# Sync migration history with actual DB state (mark all as applied)
./pocketbase migrate history-sync

Auto-migrate Mode

Enabled by default. When you change collections in the Dashboard, PocketBase auto-generates migration files in pb_migrations/.

# Start with auto-migrate (default)
./pocketbase serve

# Disable auto-migrate (production)
./pocketbase serve --automigrate=0

Workflow:

  1. Develop with auto-migrate ON — use Dashboard to design schema
  2. Migration files are auto-generated in pb_migrations/
  3. Commit these files to git
  4. Deploy: migrations run automatically on serve start
  5. In production: use --automigrate=0 to prevent Dashboard changes from generating new migrations

Migration File Format

// pb_migrations/1234567890_add_posts_collection.js

migrate(
    // UP — apply migration
    function(app) {
        var collection = new Collection({
            name: "posts",
            type: "base",
            fields: [
                { name: "title", type: "text", required: true },
                { name: "body", type: "editor" },
                { name: "author", type: "relation", collectionId: "USERS_COLLECTION_ID", cascadeDelete: false, maxSelect: 1, required: true },
                { name: "status", type: "select", values: ["draft", "published", "archived"] },
                { name: "published_at", type: "date" },
                { name: "tags", type: "relation", collectionId: "TAGS_COLLECTION_ID", maxSelect: 0 }
            ],
            indexes: [
                "CREATE INDEX idx_posts_author ON posts (author)",
                "CREATE INDEX idx_posts_status ON posts (status)",
                "CREATE UNIQUE INDEX idx_posts_title ON posts (title)"
            ],
            listRule: "",   // WARNING: "" means public access — use a filter or null to restrict
            viewRule: "",   // WARNING: "" means public access — use a filter or null to restrict
            createRule: "@request.auth.id != ''",
            updateRule: "author = @request.auth.id",
            deleteRule: "author = @request.auth.id"
        })
        app.save(collection)
    },
    // DOWN — revert migration
    function(app) {
        var collection = app.findCollectionByNameOrId("posts")
        app.delete(collection)
    }
)

Important: the app inside migrations is a transactional instance. If any error occurs, the entire migration is rolled back.

Creating Collections Programmatically

Base collection

var collection = new Collection({
    name: "posts",
    type: "base",
    fields: [
        { name: "title", type: "text", required: true, min: 3, max: 200 },
        { name: "slug", type: "text", required: true, autogenerate: { pattern: "slugify(title)" } },
        { name: "body", type: "editor" },
        { name: "cover", type: "file", maxSelect: 1, maxSize: 5242880, mimeTypes: ["image/jpeg", "image/png", "image/webp"] },
        { name: "views", type: "number", min: 0 },
        { name: "metadata", type: "json", maxSize: 2000000 },
        { name: "featured", type: "bool" },
        { name: "published_at", type: "date" }
    ]
})
app.save(collection)

Auth collection

var collection = new Collection({
    name: "users",
    type: "auth",
    fields: [
        { name: "name", type: "text", required: true },
        { name: "avatar", type: "file", maxSelect: 1, maxSize: 5242880 },
        { name: "role", type: "select", values: ["user", "editor", "admin"], required: true }
    ],
    passwordAuth: { enabled: true, identityFields: ["email", "username"] },
    oauth2: { enabled: true },
    otp: { enabled: false },
    mfa: { enabled: false },
    authToken: { duration: 604800 }  // 7 days
})
app.save(collection)

View collection

var collection = new Collection({
    name: "posts_stats",
    type: "view",
    viewQuery: "SELECT p.id, p.title, COUNT(c.id) as comments_count, p.views FROM posts p LEFT JOIN comments c ON c.post = p.id GROUP BY p.id",
    listRule: "",
    viewRule: ""
})
app.save(collection)

Modifying Existing Collections

migrate(function(app) {
    var collection = app.findCollectionByNameOrId("posts")

    // Add a new field
    collection.fields.add({
        name: "subtitle",
        type: "text",
        max: 500
    })

    // Remove a field
    collection.fields.removeByName("old_field")

    // Update API rules
    collection.listRule = "@request.auth.id != ''"
    collection.viewRule = ""

    // Add index
    collection.indexes.push("CREATE INDEX idx_posts_subtitle ON posts (subtitle)")

    app.save(collection)
}, function(app) {
    var collection = app.findCollectionByNameOrId("posts")
    collection.fields.removeByName("subtitle")
    app.save(collection)
})

Raw SQL in Migrations

migrate(function(app) {
    app.db().newQuery("ALTER TABLE posts ADD COLUMN legacy_id TEXT DEFAULT ''").execute()
    app.db().newQuery("UPDATE posts SET legacy_id = id WHERE legacy_id = ''").execute()
}, function(app) {
    app.db().newQuery("ALTER TABLE posts DROP COLUMN legacy_id").execute()
})

Warning: raw SQL bypasses PocketBase's schema cache. Run migrate collections afterward to re-sync if needed.

Settings & Superuser in Migrations

Initialize app settings

onBootstrap(function(e) {
    var settings = e.app.settings()
    settings.meta.appName = "My App"
    settings.meta.appURL = "https://myapp.com"
    settings.meta.senderName = "My App"
    settings.meta.senderAddress = "noreply@myapp.com"
    settings.smtp.enabled = true
    settings.smtp.host = "smtp.example.com"
    settings.smtp.port = 587
    settings.smtp.username = $os.getenv("SMTP_USER")
    settings.smtp.password = $os.getenv("SMTP_PASS")
    e.app.save(settings)
    return e.next()
})

Create superuser in migration

migrate(function(app) {
    var superusers = app.findCollectionByNameOrId("_superusers")
    var record = new Record(superusers)
    // IMPORTANT: always set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD env vars
    var email = $os.getenv("PB_ADMIN_EMAIL")
    var password = $os.getenv("PB_ADMIN_PASSWORD")
    if (!email || !password) {
        throw new Error("PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD env vars are required")
    }
    record.set("email", email)
    record.set("password", password)
    app.save(record)
})

Snapshot Migrations

./pocketbase migrate collections generates a complete snapshot — useful for:

  • Bootstrapping a new environment
  • Resetting migration history
  • Reviewing full schema in one file

The generated file uses app.importCollections(collections) which supports two modes:

  • Default (merge/extend): adds new collections and fields, updates existing ones, doesn't delete anything
  • Delete missing: app.importCollections(collections, true) — deletes collections/fields not in the snapshot

_migrations Table

PocketBase tracks applied migrations in the internal _migrations table:

  • id — auto-generated
  • file — migration filename
  • applied — timestamp

migrate history-sync marks all existing migration files as applied without running them — useful when importing an existing database.

Best Practices

  1. Dev: use auto-migrate + Dashboard for schema design, commit generated files
  2. Staging/Prod: deploy with --automigrate=0, migrations run on startup
  3. Always write DOWN migrations — reversibility saves you when things go wrong
  4. One concern per migration — don't mix unrelated schema changes
  5. Test migrations: apply on a copy of production data before deploying
  6. Use migrate collections periodically to snapshot current state for documentation
  7. Never edit applied migrations — create a new migration to fix issues
  8. Seed data: prefer a dedicated migration for one-time initial data; if using onBootstrap, make the seed logic idempotent (existence checks/upserts) because bootstrap runs on every app start

04 同仓库更多 Skills

davila7
davila7/claude-code-templates

wealthville-pool-scoring

Score DeFi liquidity pools before providing liquidity. Returns a 0-100 pool score and an Enter/Hold/Exit/Reduce/Avoid verdict with calibrated confidence for ~68,800 Solana pools and 575 EVM pools, plus a public miss-inclusive track record. Use when asked whether a pool is worth LPing into, which pools look best right now, or how accurate the scores have actually been.

Skill与智能体开发
★ 3.3w
davila7
davila7/claude-code-templates

technical-debt-auditor

Scans a codebase and produces a quantified technical debt report with a prioritized remediation plan. Analyzes dead code, TODO/FIXME/HACK markers, dependency staleness, complexity hotspots, code duplication signals, test coverage gaps, unused exports, and outdated patterns. Use this skill when the user asks to audit their codebase for tech debt, wants a health check of their code quality, says things like "where should I focus refactoring", "find code smells", "audit my codebase", "what technical debt do we have", "prioritize cleanup work", or asks about code quality metrics. Also trigger when the user mentions "code rot", "legacy cleanup", "refactoring priorities", or wants to understand the overall health of a project before a major effort. Trigger even if the user doesn't say "technical debt" explicitly — any request to systematically assess code quality and identify improvement priorities belongs here.

Skill与智能体开发
★ 3.3w
davila7
davila7/claude-code-templates

readonly-sql-guard

Make an agent's database access provably read-only. Use when an agent runs caller-supplied SQL against a production/ERP/analytics database (a "query" MCP tool, text-to-SQL, an admin console), or when reviewing DB-access code for write/DDL/side-effect/transaction-escape risks. Checks what a statement CALLS, not just its shape.

数据分析师后端与接口Skill与智能体开发
★ 3.3w
davila7
davila7/claude-code-templates

web-artifacts-builder

Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.

前端开发
★ 3.3w
davila7
davila7/claude-code-templates

webapp-testing

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

测试与质量前端开发
★ 3.3w
davila7
davila7/claude-code-templates

discernment-nudge

After you give a substantive answer or draft that the user may act on — advice or recommendations, drafted artifacts such as goals, plans, pitches, proposals, or emails, estimates or projections, analysis or interpretation of data, factual claims they may rely on, or a multi-step argument — invoke this skill BEFORE finalizing your reply and then, if it applies, append 2-3 short follow-up questions, each tied to something specific in what you just produced, that help the user check key facts, probe the reasoning or assumptions, and notice missing context. Do this at most once per conversation. Skip it when the user asked a trivial how-to or simple lookup, wants a purely educational explanation, asked you only to format, convert, or assemble a file from content they provided, is writing code they will run, is doing creative writing or casual chat, or already asked you to double-check, cite, or review — the skill file explains these boundaries and the exact output format.

内容创作者写作与文案Skill与智能体开发
★ 3.3w