Go migrations and extension testing
Create versioned Go migrations and test PocketBase extensions with isolated application data.
Create repeatable database changes and exercise Go extensions against a disposable PocketBase application. This workflow keeps migration files in version control and gives each test its own application lifecycle.
Before you begin
You need a Go PocketBase application with the migratecmd plugin registered, a Go module, and a separate test data directory. Use a synthetic superuser such as test@example.com; do not commit a real password or production data. The examples assume your application package is the current directory.
Create and apply a migration
Register migratecmd with the application root command. Go templates are the default, and the plugin uses a migrations directory relative to the application data directory when no directory is configured.
app := pocketbase.New()
migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{
Automigrate: osutils.IsProbablyGoRun(),
})The application exposes the migrate command when it starts.
Run the command from the application directory and provide a migration name.
go run . migrate create "add_article_status"Confirm the prompt. PocketBase creates a timestamped, snake-case .go file, such as migrations/1700000000_add_article_status.go. The timestamp is an example placeholder.
Register one migration and return any database error from the upgrade function. Keep the downgrade function focused on reversing the same change.
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
_, err := app.DB().NewQuery(
"ALTER TABLE articles ADD COLUMN status TEXT DEFAULT 'draft'",
).Execute()
return err
}, nil)
}The migration is available to the application when its package is imported, for example with _ "example.com/myapp/migrations" in a main package file.
Apply unapplied migrations explicitly during development.
go run . migrate upThe command runs the migration and records its filename in the internal migration history. New migrations can also run when the application starts with serve.
Create test data in an isolated directory, then construct a fresh tests.TestApp for the test. Bind the same hooks that production uses and let the scenario clean up the application.
const testDataDir = "./test_pb_data"
func setupTestApp(t testing.TB) *tests.TestApp {
app, err := tests.NewTestApp(testDataDir)
if err != nil {
t.Fatal(err)
}
bindAppHooks(app)
return app
}tests.NewTestApp returns an isolated app instance. A tests.ApiScenario can then check method handling, authorization, status codes, and response content.
Test authorization and responses
Use separate tokens for an ordinary auth record and a superuser. A useful scenario set checks a wrong HTTP method (405), a guest (401), an authenticated app user denied by RequireSuperuserAuth (401), and an authenticated superuser receiving 200 and the expected body. Keep the test data directory outside production data and do not point tests at a live deployment.
Troubleshooting
The create command reports a missing migration file name
Pass a name after create, for example go run . migrate create "add_profile". The command requires at least one name argument.
The migration is not discovered
Confirm that the migration package is imported by the main package. Go migrations register themselves during package initialization; an unimported package cannot contribute its migration.
Tests affect shared data
Check the argument passed to tests.NewTestApp. Use a dedicated ./test_pb_data directory and do not reuse the directory served by your development or production process.
Collection changes create unwanted intermediate migrations
Review files created while Automigrate was enabled. Remove or squash intermediate files deliberately, then run go run . migrate history-sync so migration history no longer references removed files.
Next steps
Continue with Go routes, middleware, and templates, then review migrations and schema delivery before deploying schema changes.