Goose for Database Migrations
When developing a database schema, it’s useful to represent it as a series of incremental changes that handle data migrations alongside the schema migrations. Goose is a great tool for this when working with SQL databases with its simplicity and first-class Go integration.
Goose migrations are stored in a directory either by date or with
a sequence number, and can be created with the create command.
Within the migration, the block annotated with the +goose Up
comment is executed to apply the migration, and the block under
+goose Down is run to roll it back. A basic migration might look
like this:
-- +goose Up
CREATE TABLE test (
name varchar PRIMARY KEY
);
-- +goose Down
DROP TABLE test;
Go Integration
Integrating goose with a Go application can streamline the process of managing database migrations by allowing distribution of the migrations directly with the binary via Go’s embedded filesystems. Additionally, since the database object is passed directly to goose when using the package it’s easy to reuse database connection parameters.
The following example package exports functions to apply, roll back,
and view database migrations embedded from the migrations directory.
package migrate
import (
"database/sql"
"embed"
"github.com/pressly/goose/v3"
)
//go:embed migrations/*.sql
var migrations embed.FS
func initGoose() error {
goose.SetBaseFS(migrations)
return goose.SetDialect("postgres")
}
func Up(db *sql.DB) error {
if err := initGoose(); err != nil {
return err
}
return goose.Up(db, "migrations")
}
func Down(db *sql.DB) error {
if err := initGoose(); err != nil {
return err
}
return goose.Down(db, "migrations")
}
func Status(db *sql.DB) error {
if err := initGoose(); err != nil {
return err
}
return goose.Status(db, "migrations")
}
To see what else the goose package provides, see its documentation.