docs(migrate): require Goose migration authoring tools
Documentation / docs (pull_request) Successful in 21s
ci / check (pull_request) Successful in 11m31s

This commit is contained in:
end committed 2026-10-27 20:42:03 -07:00
1 parent c1164ca304
commit d1be73bfcf
2 files changed
+27 -56

No files matched your search

+24 -53
View File
@@ -5,6 +5,14 @@
It returns `*goose.Provider` directly: Goose owns execution, version tracking, It returns `*goose.Provider` directly: Goose owns execution, version tracking,
status, and errors. There is no lifecycle dependency or background work. status, and errors. There is no lifecycle dependency or background work.
Consumers must create migration files with Goose's
[`create` command](https://pressly.github.io/goose/documentation/cli-commands/#create).
For timestamp-to-sequential reconciliation before deployment, use its
[`fix` command](https://pressly.github.io/goose/documentation/cli-commands/#fix)
as described in [hybrid versioning](https://github.com/pressly/goose#hybrid-versioning).
These commands edit source files before embedding; `fix` does not update database
history. Never renumber migrations already applied to shared databases.
Embed migrations in the application's binary and run them before serving traffic: Embed migrations in the application's binary and run them before serving traffic:
```go ```go
@@ -40,65 +48,28 @@ not defer it when sharing the pool with the application. Use `"."` for SQL files
at the embedded root. Files in the selected directory are discovered directly, at the embedded root. Files in the selected directory are discovered directly,
without recursively searching subdirectories. without recursively searching subdirectories.
Use unique positive versions and Goose's migration creator naming convention: Preserve Goose's creator/fix filenames and ship the complete migration history.
zero-padded sequential names such as `00007_users.sql` and `00010_events.sql`, or The pinned Goose SQL-only provider relies on lexical filename order matching
fixed-width timestamps such as `20261027114500_create_users.sql`. Filenames must numeric version order. Timestamp versions and gaps are supported; never derive
sort lexically in numeric version order, including when mixing naming schemes; versions from file counts. For operations, errors, and SQL annotations, use the
choose padding wide enough for the complete history. Goose v3.29.0 preserves [Provider API](https://pkg.go.dev/github.com/pressly/goose/v3#Provider) and
lexical source order for SQL-only providers, so arbitrary unpadded names such as [SQL migration docs](https://pressly.github.io/goose/documentation/annotations/).
`7_users.sql` and `10_events.sql` are unsupported by this house convention: they
can produce incorrect latest versions and source/status ordering. This package
does not rename or normalize migration files.
Never derive a version from a file count or add one to the current version. For Go functions, use Goose's
Keep applied migrations immutable and ship the complete history. Goose rejects [provider-local registration](https://pressly.github.io/goose/documentation/provider/#withgomigrations):
newly introduced migrations below the current version by default. pass fresh `goose.NewGoMigration` values as the trailing arguments to `migrate.New`.
The creator's default Go template instead calls `goose.AddMigrationContext` from
```sql `init`; replace that registration with provider-local construction. Global
-- +goose Up registration is disabled to keep each provider's migration set isolated and avoid
CREATE TABLE users (id BIGINT PRIMARY KEY); import side effects. If `fix` renames Go migrations, update their explicit
registration versions to match. Versions must be unique across SQL and Go files.
-- +goose Down
DROP TABLE users;
```
Goose runs each migration in a transaction by default. Its annotations support
statement blocks and explicit `NO TRANSACTION` where required; such migrations
and nontransactional database DDL can leave partial effects on failure. Down
migrations execute application-authored SQL and may delete data.
| Operation | Provider method |
| --- | --- |
| Apply all pending migrations | `Up(ctx)` |
| Apply pending versions through a target, inclusive | `UpTo(ctx, version)` |
| Roll back versions above a target; zero removes all | `DownTo(ctx, version)` |
| Inspect each migration's state | `Status(ctx)` |
| Current database version | `GetDBVersion(ctx)` |
| Current and latest available versions | `GetVersions(ctx)` |
| Detect pending migrations | `HasPending(ctx)` |
Targets are numeric version bounds, so gaps and timestamps work without special
handling. Up on a fully migrated database succeeds with no results. Operations
may create Goose's `goose_db_version` table even when only inspecting state.
Execution errors retain Goose's details; use `errors.As` with
`*goose.PartialError` to inspect applied and failed migrations. Transactional
failure leaves the database at the last committed migration version. Operation
logs use the injected slog logger; callers handle and log returned errors.
For Go functions, pass migrations created with `goose.NewGoMigration(version,
up, down)` as the trailing arguments to `migrate.New`. Use `goose.GoFunc.RunTx`
for transactional work or `RunDB` for work requiring its own connections. Each
provider should receive its own migration instances. Versions must be unique
across SQL and Go migrations. Global registration is disabled; no `init` or
`goose.AddMigration` calls are needed.
Postgres providers automatically use Goose's default session advisory locker. Postgres providers automatically use Goose's default session advisory locker.
Concurrent startup calls from separate providers/processes serialize migration Concurrent startup calls from separate providers/processes serialize migration
execution and recheck applied versions under the lock. The default lock ID execution and recheck applied versions under the lock. The default lock ID
serializes Goose migrations throughout the same database, including different serializes Goose migrations throughout the same database, including different
schemas; lock acquisition retries for about five minutes and unlock retries for schemas. Use a direct connection or a session-pooling proxy: transaction pooling
about one minute, subject to the operation context. Use a direct connection or cannot preserve session locks.
a session-pooling proxy: transaction pooling cannot preserve session locks.
`RunDB` Go migrations need spare pool connections while the locked session is `RunDB` Go migrations need spare pool connections while the locked session is
held; avoid a one-connection pool for them. held; avoid a one-connection pool for them.
+3 -3
View File
@@ -24,9 +24,9 @@ import (
// affinity (transaction-pooling proxies cannot safely hold session locks). // affinity (transaction-pooling proxies cannot safely hold session locks).
// //
// Use the returned Provider's Up, UpTo, DownTo, Status, GetDBVersion, GetVersions, // Use the returned Provider's Up, UpTo, DownTo, Status, GetDBVersion, GetVersions,
// and HasPending methods directly. Filenames must sort lexically in numeric // and HasPending methods directly. Create migration files with Goose's create
// version order: use zero-padded sequential or fixed-width timestamp prefixes, // command; lexical filename order must match numeric version order. Go migrations
// as produced by Goose's migration creator. Global Go registration is ignored. // are registered per provider; global Go registration is ignored.
func New(db *sql.DB, dialect goose.Dialect, files embed.FS, dir string, logger *slog.Logger, migrations ...*goose.Migration) (*goose.Provider, error) { func New(db *sql.DB, dialect goose.Dialect, files embed.FS, dir string, logger *slog.Logger, migrations ...*goose.Migration) (*goose.Provider, error) {
for i, migration := range migrations { for i, migration := range migrations {
if migration == nil { if migration == nil {