Database migrations
PatchBase uses Goose for database migrations. Migration files are SQL files stored in internal/migrations/files/.
Creating a migration
- Create a new SQL file in
internal/migrations/files/following the numbering convention:
internal/migrations/files/005_create_new_table.sql
- Write the migration with up and down sections:
-- +goose Up
CREATE TABLE new_table (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- +goose Down
DROP TABLE new_table;
- Add the file to
embedsrcsininternal/migrations/BUILD.bazel:
go_library(
name = "migrations",
srcs = ["migrate.go"],
embedsrcs = [
"files/001_initial_schema.sql",
"files/002_create_hosts.sql",
"files/003_create_advisories.sql",
"files/004_create_host_ssh_pull.sql",
"files/005_create_new_table.sql", # add your new file here
],
...
)
important
If you forget to add the file to embedsrcs, the migration won't be embedded in the binary and won't run.
Running migrations
# Using the CLI
bazel run //cmd/patchbase-server -- migrate
# With a custom database URL
bazel run //cmd/patchbase-server -- migrate --database-url "postgres://..."
Migrations are idempotent — running them when everything is up to date is a no-op.
Regenerating schema and sqlc bindings
After adding or modifying a migration, regenerate the database schema and sqlc Go bindings:
bazel run //db:regen_schema
This:
- Spins up a temporary PostgreSQL container
- Applies all migrations
- Updates
db/schema.sql - Regenerates Go sqlc bindings under
internal/sql/
Updating the test database
After schema changes, recreate the test database volume:
docker compose -f compose.test.yaml down -v
docker compose -f compose.test.yaml up -d
Or apply migrations manually:
bazel run //cmd/patchbase-server -- migrate \
--database-url "postgres://postgres:postgres@localhost:5433/patchbase_test?sslmode=disable"