Skip to main content
Version: 1.8.0

Migrations API Reference

Everything that changes a schema: the reflective helpers (Migrate, Sync, CreateIndex, AddForeignKey) and the versioned migrator in the migrate package.

For which path to use when — quick reflective setup versus reviewable versioned migrations — see the Migrations guide.

SymbolSignaturePurpose
Client.MigrateMigrate(ctx, models ...any) errorCreates missing tables (and m2m join tables).
Client.SyncSync(ctx, opts SyncOptions, models ...any) errorReconciles existing tables with model metadata.
Client.CreateIndexCreateIndex(ctx, table, indexName string, columns []string, unique bool) errorCreates a simple index.
Client.AddForeignKeyAddForeignKey(ctx, table, constraintName string, columns []string, refTable string, refColumns []string, onDelete, onUpdate string) errorAdds a foreign key constraint.
migrate.RegisterRegister(m *Migration)Registers a migration in the global registry.
migrate.ResetReset()Clears the registry (tests).
migrate.NewMigratorNewMigrator(client *quark.Client) *MigratorBinds a migrator to a client.
Migrator.InitInit(ctx) errorCreates the quark_migrations tracking table.
Migrator.UpUp(ctx, steps int) errorApplies pending migrations (ID order).
Migrator.UpDryRunUpDryRun(ctx, steps int) errorPrints pending migrations without running them.
Migrator.DownDown(ctx, steps int) errorReverts applied migrations (reverse ID order).

Client Schema Helpers

Migrate(ctx context.Context, models ...any) error

Creates missing tables for the given models.

err := client.Migrate(ctx, &User{}, &Order{}, &Product{})

Migrate also creates many-to-many join tables for relations tagged rel:"many_to_many" with an m2m tag.

Sync(ctx context.Context, opts SyncOptions, models ...any) error

Synchronizes existing tables with model metadata.

err := client.Sync(ctx, quark.SyncOptions{}, &User{})

Supported sync operations:

ChangeSupport
Missing tableCalls Migrate unless DryRun is true.
New columnAdds the column.
Renamed columnUses quark:"rename:old_col".
Removed columnDrops only when the client's Limits.SafeMigrations is false.
type SyncOptions struct {
DryRun bool // Log the SQL but don't execute it.
NoTransaction bool // Don't wrap the sync in a transaction.
}

Dropping a removed column is gated by Limits.SafeMigrations, not by SyncOptions. DefaultLimits() sets SafeMigrations: true, so removed columns are left in place until you opt into destructive sync:

limits := quark.DefaultLimits()
limits.SafeMigrations = false // allow DROP COLUMN
client, _ := quark.New("postgres", dsn, quark.WithLimits(limits))

CreateIndex(ctx, table, indexName string, columns []string, unique bool) error

Creates a simple index.

err := client.CreateIndex(
ctx,
"users",
"idx_users_email",
[]string{"email"},
true,
)

AddForeignKey(ctx, table, constraintName string, columns []string, refTable string, refColumns []string, onDelete, onUpdate string) error

Adds a foreign key constraint.

err := client.AddForeignKey(
ctx,
"orders",
"fk_orders_user",
[]string{"user_id"},
"users",
[]string{"id"},
"CASCADE",
"",
)

Versioned Migrations

migrate.Register(m *Migration)

Registers a migration in the global migration registry.

migrate.Register(&migrate.Migration{
ID: "202605050001_add_email_index",
Name: "add email index",
Up: func(ctx context.Context, client *quark.Client) error {
return client.CreateIndex(ctx, "users", "idx_users_email", []string{"email"}, true)
},
Down: func(ctx context.Context, client *quark.Client) error {
return client.Exec(ctx, "DROP INDEX idx_users_email")
},
})

Migration IDs are sorted lexicographically. Use timestamp-like IDs.

type Migration struct {
ID string
Name string
Message string
Up func(ctx context.Context, client *quark.Client) error
Down func(ctx context.Context, client *quark.Client) error
}

migrate.Reset()

Clears the migration registry. Intended for tests.

Migrator

migrate.NewMigrator(client *quark.Client) *Migrator

Creates a migrator bound to a client.

migrator := migrate.NewMigrator(client)

The migrator stores applied migration IDs in quark_migrations.

Init(ctx context.Context) error

Creates the migration tracking table if needed.

err := migrator.Init(ctx)

Up(ctx context.Context, steps int) error

Applies pending migrations in ID order.

err := migrator.Up(ctx, 0) // apply all pending
err = migrator.Up(ctx, 2) // apply at most two

UpDryRun(ctx context.Context, steps int) error

Prints pending migrations without executing their Up functions.

err := migrator.UpDryRun(ctx, 0)

Down(ctx context.Context, steps int) error

Reverts applied migrations in reverse ID order.

err := migrator.Down(ctx, 1)

Raw SQL Requirement

migrate.Migrator uses client.Exec for its tracking table changes. Configure the migration client with AllowRawQueries: true:

limits := quark.DefaultLimits()
limits.AllowRawQueries = true

client, err := quark.New("postgres", dsn,
quark.WithLimits(limits),
)

High-level helpers such as Migrate, Sync, CreateIndex, and AddForeignKey do not require AllowRawQueries.