goose for Go: complete guide with examples
\n\nWhat it is and why you need it
\nThe goose library (Go Object-Oriented SQL Environment) is a powerful tool for managing database migrations in the Go ecosystem. Unlike built-in solutions, goose provides a declarative approach to database schema versioning, allowing developers to describe changes in SQL or Go code. The main task of goose is to automate the process of applying and rolling back database structure changes, which is critical for team development and CI/CD pipelines.
\nWhy do you need goose? First, it solves the problem of database schema synchronization between developers: each team member can apply the latest migrations with a single command. Second, goose supports versioning — each migration has a unique number, allowing you to accurately determine which changes have already been applied. Third, the library can work with various DBMS (PostgreSQL, MySQL, SQLite, ClickHouse and others) through a unified interface, simplifying switching between environments.
\nThe key advantage of goose over alternatives (e.g., golang-migrate/migrate) is support for migrations in Go, not just SQL. You can write complex migrations with business logic, use transactions, and call external APIs. Additionally, goose provides built-in support for embed (embedding migrations into the binary), which is ideal for production environments.
Installation
\nInstallation of goose is done through the standard Go package manager. First, make sure you have Go version 1.18 or higher installed.
\ngo install github.com/pressly/goose/v3/cmd/goose@latest\n After installation, check the version:
\ngoose --version\n To use goose as a library in your project, add the dependency:
\ngo get github.com/pressly/goose/v3\n You will also need a driver for your DBMS. For example, for PostgreSQL:
\ngo get github.com/lib/pq\n For MySQL:
\ngo get github.com/go-sql-driver/mysql\n For SQLite:
\ngo get github.com/mattn/go-sqlite3\n Quick start — minimal working example
\nLet's create a simple project to demonstrate the basic capabilities of goose.
\n1. Create a project directory and initialize the module:
\nmkdir goose-demo && cd goose-demo\ngo mod init goose-demo\n 2. Create a directory for migrations:
\nmkdir migrations\n 3. Create the first migration in SQL. File migrations/001_create_users.sql:
-- +goose Up\nCREATE TABLE users (\n id SERIAL PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n email VARCHAR(255) UNIQUE NOT NULL,\n created_at TIMESTAMP DEFAULT NOW()\n);\n\n-- +goose Down\nDROP TABLE users;\n 4. Create a main.go file for programmatically running migrations:
package main\n\nimport (\n "database/sql"\n "embed"\n "log"\n\n "github.com/pressly/goose/v3"\n _ "github.com/lib/pq"\n)\n\n//go:embed migrations/*.sql\nvar migrations embed.FS\n\nfunc main() {\n // Connecting to the database\n db, err := sql.Open("postgres", "host=localhost port=5432 user=postgres password=postgres dbname=testdb sslmode=disable")\n if err != nil {\n log.Fatal(err)\n }\n defer db.Close()\n\n // Setting the migration source from embed.FS\n goose.SetBaseFS(migrations)\n\n // Running migrations to the latest version