Convert Figma logo to code with AI

pressly logogoose

A database migration tool. Supports SQL migrations and Go functions.

6,594
506
6,594
76

Top Related Projects

2,288

Database migrations. CLI and Golang library.

SQL schema migration tool for Go.

8,090

Flyway by Redgate • Database Migrations Made Easy.

Main Liquibase Source

5,223

🚀 A lightweight, framework-agnostic database migration tool.

Quick Overview

Goose is a database migration tool written in Go. It allows developers to manage and version control database schema changes, supporting multiple database systems including PostgreSQL, MySQL, SQLite, and others. Goose provides a command-line interface and can be embedded in Go applications for programmatic control of migrations.

Pros

  • Supports multiple database systems, offering flexibility for different project requirements
  • Can be used as both a standalone CLI tool and embedded in Go applications
  • Provides both up and down migrations for easy rollback of changes
  • Offers a simple and intuitive API for creating and managing migrations

Cons

  • Limited to Go language ecosystem, which may not be suitable for all projects
  • Lacks some advanced features found in more comprehensive migration tools
  • Documentation could be more extensive, especially for advanced use cases
  • May require additional setup compared to database-specific migration tools

Code Examples

Creating a new migration:

package main

import (
    "database/sql"
    "github.com/pressly/goose/v3"
)

func main() {
    if err := goose.Create(db, "migrations", "create_users_table", "sql"); err != nil {
        panic(err)
    }
}

Running migrations:

package main

import (
    "database/sql"
    "github.com/pressly/goose/v3"
)

func main() {
    db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
    if err != nil {
        panic(err)
    }

    if err := goose.Up(db, "migrations"); err != nil {
        panic(err)
    }
}

Rolling back migrations:

package main

import (
    "database/sql"
    "github.com/pressly/goose/v3"
)

func main() {
    db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
    if err != nil {
        panic(err)
    }

    if err := goose.Down(db, "migrations"); err != nil {
        panic(err)
    }
}

Getting Started

  1. Install Goose:

    go get -u github.com/pressly/goose/v3/cmd/goose
    
  2. Create a migration:

    goose create create_users_table sql
    
  3. Edit the generated SQL file in the migrations folder.

  4. Run the migration:

    goose postgres "user=postgres dbname=test sslmode=disable" up
    
  5. To use Goose programmatically, import the package and use its functions as shown in the code examples above.

Competitor Comparisons

2,288

Database migrations. CLI and Golang library.

Pros of migrate

  • Supports a wider range of databases, including NoSQL options like MongoDB
  • Offers CLI, Go library, and Docker image for easier integration
  • Provides more flexibility in migration file naming conventions

Cons of migrate

  • Less active maintenance and slower issue resolution
  • More complex setup and configuration process
  • Limited built-in support for certain advanced migration scenarios

Code Comparison

migrate:

m, err := migrate.New("file://migrations", "postgres://localhost:5432/database")
if err != nil {
    log.Fatal(err)
}
m.Steps(2)

goose:

if err := goose.SetDialect("postgres"); err != nil {
    log.Fatal(err)
}
if err := goose.Up(db, "migrations"); err != nil {
    log.Fatal(err)
}

Both libraries offer straightforward ways to run migrations, but goose's API is slightly more concise and requires less initial setup. migrate provides more flexibility in specifying the migration source and database URL, while goose relies on a pre-existing database connection.

Overall, migrate offers more features and database support, making it suitable for complex projects with diverse requirements. goose, on the other hand, provides a simpler and more streamlined experience, making it ideal for projects that prioritize ease of use and maintainability.

SQL schema migration tool for Go.

Pros of sql-migrate

  • Supports multiple database types out of the box (MySQL, PostgreSQL, SQLite)
  • Offers both CLI and library usage for flexibility
  • Provides a web-based migration status viewer

Cons of sql-migrate

  • Less active development and fewer recent updates
  • Smaller community and fewer contributors
  • Limited documentation compared to Goose

Code Comparison

sql-migrate:

migrations := &migrate.FileMigrationSource{
    Dir: "migrations",
}

n, err := migrate.Exec(db, "mysql", migrations, migrate.Up)
if err != nil {
    // Handle error
}

Goose:

if err := goose.Up(db, "migrations"); err != nil {
    // Handle error
}

Both Goose and sql-migrate are Go-based database migration tools, but they differ in their approach and features. Goose focuses on simplicity and ease of use, with a more active development community. It supports various databases and offers a straightforward API. sql-migrate provides more flexibility with its multiple database support and web-based status viewer, but has seen less recent development activity. The code comparison shows that both tools have relatively simple APIs for executing migrations, with Goose having a slightly more concise syntax. When choosing between the two, consider factors such as database support, community activity, and specific feature requirements for your project.

8,090

Flyway by Redgate • Database Migrations Made Easy.

Pros of Flyway

  • Supports a wider range of databases, including Oracle, SQL Server, and DB2
  • Offers more advanced features like undo migrations and callbacks
  • Provides commercial support and enterprise-grade features

Cons of Flyway

  • More complex setup and configuration compared to Goose
  • Steeper learning curve for beginners
  • Requires Java runtime, which may not be ideal for all environments

Code Comparison

Flyway migration:

CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(100) UNIQUE NOT NULL
);

Goose migration:

func (m *Migration) Up(tx *sql.Tx) error {
    _, err := tx.Exec(`
        CREATE TABLE users (
            id INT PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            email VARCHAR(100) UNIQUE NOT NULL
        );
    `)
    return err
}

Both Flyway and Goose use SQL for migrations, but Goose wraps the SQL in Go functions, allowing for more programmatic control. Flyway uses plain SQL files or Java-based migrations, offering flexibility but potentially less integration with Go-based projects.

Main Liquibase Source

Pros of Liquibase

  • Supports multiple database types, including Oracle, SQL Server, MySQL, and PostgreSQL
  • Offers a wide range of change types and refactoring operations
  • Provides rollback functionality for easier version control and error recovery

Cons of Liquibase

  • More complex setup and configuration compared to Goose
  • Steeper learning curve due to its extensive feature set
  • Can be slower for simple migration tasks

Code Comparison

Goose migration example:

-- +goose Up
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT,
    created_at TIMESTAMP
);

-- +goose Down
DROP TABLE users;

Liquibase migration example:

<changeSet id="1" author="example">
    <createTable tableName="users">
        <column name="id" type="int" autoIncrement="true">
            <constraints primaryKey="true" nullable="false"/>
        </column>
        <column name="name" type="varchar(255)"/>
        <column name="created_at" type="timestamp"/>
    </createTable>
</changeSet>

Goose focuses on simplicity with SQL-based migrations, while Liquibase uses XML (or other formats) for more complex, database-agnostic migrations. Goose is generally easier to set up and use for Go projects, while Liquibase offers more advanced features and broader database support.

5,223

🚀 A lightweight, framework-agnostic database migration tool.

Pros of dbmate

  • Supports multiple database types (MySQL, PostgreSQL, SQLite) out of the box
  • Provides a standalone binary, making it easy to use without Go installation
  • Offers automatic schema dump functionality

Cons of dbmate

  • Less flexible for custom Go integrations compared to goose
  • May have a steeper learning curve for users familiar with Go-specific tools
  • Limited to SQL migrations, while goose supports both SQL and Go migrations

Code Comparison

dbmate migration:

-- migrate:up
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name VARCHAR(255)
);

-- migrate:down
DROP TABLE users;

goose migration:

package migrations

import "database/sql"

func Up_20210101000000(tx *sql.Tx) error {
    _, err := tx.Exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR(255))`)
    return err
}

func Down_20210101000000(tx *sql.Tx) error {
    _, err := tx.Exec(`DROP TABLE users`)
    return err
}

Both tools offer similar functionality for database migrations, but goose provides more flexibility with Go-based migrations, while dbmate focuses on SQL migrations and cross-database support.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

goose

Goose
CI Go
Reference Go Report
Card

Goose is a database migration tool. Both a CLI and a library.

Manage your database schema by creating incremental SQL changes or Go functions.

Features

  • Works against multiple databases:
    • Postgres, MySQL, SQLite, YDB, ClickHouse, MSSQL, Vertica, and more.
  • Supports Go migrations written as plain functions.
  • Supports embedded migrations.
  • Out-of-order migrations.
  • Seeding data.
  • Environment variable substitution in SQL migrations.
  • ... and more.

Install

go install github.com/pressly/goose/v3/cmd/goose@latest

This will install the goose binary to your $GOPATH/bin directory.

Binary too big? Build a lite version by excluding the drivers you don't need:

go build -tags='no_postgres no_mysql no_sqlite3 no_ydb' -o goose ./cmd/goose

# Available build tags:
#   no_clickhouse  no_libsql   no_mssql    no_mysql
#   no_postgres    no_sqlite3  no_vertica  no_ydb

For macOS users goose is available as a Homebrew Formulae:

brew install goose

See installation documentation for more details.

Usage

Click to show goose help output
Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND

or

Set environment key
GOOSE_DRIVER=DRIVER
GOOSE_DBSTRING=DBSTRING
GOOSE_MIGRATION_DIR=MIGRATION_DIR

Usage: goose [OPTIONS] COMMAND

Drivers:
    postgres
    mysql
    sqlite3
    mssql
    redshift
    tidb
    clickhouse
    vertica
    ydb

Examples:
    goose sqlite3 ./foo.db status
    goose sqlite3 ./foo.db create init sql
    goose sqlite3 ./foo.db create add_some_column sql
    goose sqlite3 ./foo.db create fetch_user_data go
    goose sqlite3 ./foo.db up

    goose postgres "user=postgres dbname=postgres sslmode=disable" status
    goose mysql "user:password@/dbname?parseTime=true" status
    goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
    goose tidb "user:password@/dbname?parseTime=true" status
    goose mssql "sqlserver://user:password@dbname:1433?database=master" status
    goose clickhouse "tcp://127.0.0.1:9000" status
    goose vertica "vertica://user:password@localhost:5433/dbname?connection_load_balance=1" status
    goose ydb "grpcs://localhost:2135/local?go_query_mode=scripting&go_fake_tx=scripting&go_query_bind=declare,numeric" status

    GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose status
    GOOSE_DRIVER=sqlite3 GOOSE_DBSTRING=./foo.db goose create init sql
    GOOSE_DRIVER=postgres GOOSE_DBSTRING="user=postgres dbname=postgres sslmode=disable" goose status
    GOOSE_DRIVER=mysql GOOSE_DBSTRING="user:password@/dbname" goose status
    GOOSE_DRIVER=redshift GOOSE_DBSTRING="postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" goose status
    GOOSE_DRIVER=clickhouse GOOSE_DBSTRING="clickhouse://user:password@qwerty.clickhouse.cloud:9440/dbname?secure=true&skip_verify=false" goose status

Options:

  -allow-missing
        applies missing (out-of-order) migrations
  -certfile string
        file path to root CA's certificates in pem format (only support on mysql)
  -dir string
        directory with migration files (default ".", can be set via the GOOSE_MIGRATION_DIR env variable).
  -h    print help
  -no-color
        disable color output (NO_COLOR env variable supported)
  -no-versioning
        apply migration commands with no versioning, in file order, from directory pointed to
  -s    use sequential numbering for new migrations
  -ssl-cert string
        file path to SSL certificates in pem format (only support on mysql)
  -ssl-key string
        file path to SSL key in pem format (only support on mysql)
  -table string
        migrations table name (default "goose_db_version")
  -timeout duration
        maximum allowed duration for queries to run; e.g., 1h13m
  -v    enable verbose mode
  -version
        print version

Commands:
    up                   Migrate the DB to the most recent version available
    up-by-one            Migrate the DB up by 1
    up-to VERSION        Migrate the DB to a specific VERSION
    down                 Roll back the version by 1
    down-to VERSION      Roll back to a specific VERSION
    redo                 Re-run the latest migration
    reset                Roll back all migrations
    status               Dump the migration status for the current DB
    version              Print the current version of the database
    create NAME [sql|go] Creates new migration file with the current timestamp
    fix                  Apply sequential ordering to migrations
    validate             Check migration files without running them

Commonly used commands:

create â€¢  up â€¢  up-to â€¢  down â€¢  down-to â€¢  status â€¢  version

create

Create a new SQL migration.

$ goose create add_some_column sql
$ Created new file: 20170506082420_add_some_column.sql

$ goose -s create add_some_column sql
$ Created new file: 00001_add_some_column.sql

Edit the newly created file to define the behavior of your migration.

You can also create a Go migration, if you then invoke it with your own goose binary:

$ goose create fetch_user_data go
$ Created new file: 20170506082421_fetch_user_data.go

up

Apply all available migrations.

$ goose up
$ OK    001_basics.sql
$ OK    002_next.sql
$ OK    003_and_again.go

up-to

Migrate up to a specific version.

$ goose up-to 20170506082420
$ OK    20170506082420_create_table.sql

up-by-one

Migrate up a single migration from the current version

$ goose up-by-one
$ OK    20170614145246_change_type.sql

down

Roll back a single migration from the current version.

$ goose down
$ OK    003_and_again.go

down-to

Roll back migrations to a specific version.

$ goose down-to 20170506082527
$ OK    20170506082527_alter_column.sql

Or, roll back all migrations (careful!):

$ goose down-to 0

status

Print the status of all migrations:

$ goose status
$   Applied At                  Migration
$   =======================================
$   Sun Jan  6 11:25:03 2013 -- 001_basics.sql
$   Sun Jan  6 11:25:03 2013 -- 002_next.sql
$   Pending                  -- 003_and_again.go

Note: for MySQL parseTime flag must be enabled.

Note: for MySQL multiStatements must be enabled. This is required when writing multiple queries separated by ';' characters in a single sql file.

version

Print the current version of the database:

$ goose version
$ goose: version 002

Migrations

goose supports migrations written in SQL or in Go.

SQL Migrations

A sample SQL migration looks like:

-- +goose Up
CREATE TABLE post (
    id int NOT NULL,
    title text,
    body text,
    PRIMARY KEY(id)
);

-- +goose Down
DROP TABLE post;

Each migration file must have exactly one -- +goose Up annotation. The -- +goose Down annotation is optional. If the file has both annotations, then the -- +goose Up annotation must come first.

Notice the annotations in the comments. Any statements following -- +goose Up will be executed as part of a forward migration, and any statements following -- +goose Down will be executed as part of a rollback.

By default, all migrations are run within a transaction. Some statements like CREATE DATABASE, however, cannot be run within a transaction. You may optionally add -- +goose NO TRANSACTION to the top of your migration file in order to skip transactions within that specific migration file. Both Up and Down migrations within this file will be run without transactions.

By default, SQL statements are delimited by semicolons - in fact, query statements must end with a semicolon to be properly recognized by goose.

More complex statements (PL/pgSQL) that have semicolons within them must be annotated with -- +goose StatementBegin and -- +goose StatementEnd to be properly recognized. For example:

-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
  create_query text;
BEGIN
  FOR create_query IN SELECT
      'CREATE TABLE IF NOT EXISTS histories_'
      || TO_CHAR( d, 'YYYY_MM' )
      || ' ( CHECK( created_at >= timestamp '''
      || TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
      || ''' AND created_at < timestamp '''
      || TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
      || ''' ) ) inherits ( histories );'
    FROM generate_series( $1, $2, '1 month' ) AS d
  LOOP
    EXECUTE create_query;
  END LOOP;  -- LOOP END
END;         -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd

Goose supports environment variable substitution in SQL migrations through annotations. To enable this feature, use the -- +goose ENVSUB ON annotation before the queries where you want substitution applied. It stays active until the -- +goose ENVSUB OFF annotation is encountered. You can use these annotations multiple times within a file.

This feature is disabled by default for backward compatibility with existing scripts.

For PL/pgSQL functions or other statements where substitution is not desired, wrap the annotations explicitly around the relevant parts. For example, to exclude escaping the ** characters:

-- +goose StatementBegin
CREATE OR REPLACE FUNCTION test_func()
RETURNS void AS $$
-- +goose ENVSUB ON
BEGIN
	RAISE NOTICE '${SOME_ENV_VAR}';
END;
-- +goose ENVSUB OFF
$$ LANGUAGE plpgsql;
-- +goose StatementEnd
Supported expansions (click here to expand):
  • ${VAR} or $VAR - expands to the value of the environment variable VAR
  • ${VAR:-default} - expands to the value of the environment variable VAR, or default if VAR is unset or null
  • ${VAR-default} - expands to the value of the environment variable VAR, or default if VAR is unset
  • ${VAR?err_msg} - expands to the value of the environment variable VAR, or prints err_msg and error if VAR unset
  • ${VAR:?err_msg} - expands to the value of the environment variable VAR, or prints err_msg and error if VAR unset or null. THIS IS NOT SUPPORTED

See mfridman/interpolate for more details on supported expansions.

Embedded sql migrations

Go 1.16 introduced new feature: compile-time embedding files into binary and corresponding filesystem abstraction.

This feature can be used only for applying existing migrations. Modifying operations such as fix and create will continue to operate on OS filesystem even if using embedded files. This is expected behaviour because io/fs interfaces allows read-only access.

Make sure to configure the correct SQL dialect, see dialect.go for supported SQL dialects.

Example usage, assuming that SQL migrations are placed in the migrations directory:

package main

import (
    "database/sql"
    "embed"

    "github.com/pressly/goose/v3"
)

//go:embed migrations/*.sql
var embedMigrations embed.FS

func main() {
    var db *sql.DB
    // setup database

    goose.SetBaseFS(embedMigrations)

    if err := goose.SetDialect("postgres"); err != nil {
        panic(err)
    }

    if err := goose.Up(db, "migrations"); err != nil {
        panic(err)
    }

    // run app
}

Note that we pass "migrations" as directory argument in Up because embedding saves directory structure.

Go Migrations

  1. Create your own goose binary, see example
  2. Import github.com/pressly/goose
  3. Register your migration functions
  4. Run goose command, ie. goose.Up(db *sql.DB, dir string)

A sample Go migration 00002_users_add_email.go file looks like:

package migrations

import (
	"database/sql"

	"github.com/pressly/goose/v3"
)

func init() {
	goose.AddMigration(Up, Down)
}

func Up(tx *sql.Tx) error {
	_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
	if err != nil {
		return err
	}
	return nil
}

func Down(tx *sql.Tx) error {
	_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
	if err != nil {
		return err
	}
	return nil
}

Note that Go migration files must begin with a numeric value, followed by an underscore, and must not end with *_test.go.

Hybrid Versioning

Please, read the versioning problem first.

By default, if you attempt to apply missing (out-of-order) migrations goose will raise an error. However, If you want to apply these missing migrations pass goose the -allow-missing flag, or if using as a library supply the functional option goose.WithAllowMissing() to Up, UpTo or UpByOne.

However, we strongly recommend adopting a hybrid versioning approach, using both timestamps and sequential numbers. Migrations created during the development process are timestamped and sequential versions are ran on production. We believe this method will prevent the problem of conflicting versions when writing software in a team environment.

To help you adopt this approach, create will use the current timestamp as the migration version. When you're ready to deploy your migrations in a production environment, we also provide a helpful fix command to convert your migrations into sequential order, while preserving the timestamp ordering. We recommend running fix in the CI pipeline, and only when the migrations are ready for production.

Credit

The gopher mascot was designed by Renée French / CC 3.0. For more info check out the Go Blog. Adapted by Ellen.

License

Licensed under MIT License