Convert Figma logo to code with AI

rubenv logosql-migrate

SQL schema migration tool for Go.

3,179
271
3,179
86

Top Related Projects

14,958

Database migrations. CLI and Golang library.

6,594

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

5,223

🚀 A lightweight, framework-agnostic database migration tool.

8,090

Flyway by Redgate • Database Migrations Made Easy.

Main Liquibase Source

Quick Overview

sql-migrate is a database migration tool for Go, allowing developers to manage database schema changes in a version-controlled manner. It supports multiple database systems and provides a simple CLI for executing migrations.

Pros

  • Easy to integrate with existing Go projects
  • Supports multiple database systems (MySQL, PostgreSQL, SQLite, etc.)
  • Allows both up and down migrations for easy rollbacks
  • Provides a simple CLI for executing migrations

Cons

  • Limited to SQL-based migrations (no support for NoSQL databases)
  • Requires manual writing of SQL statements for migrations
  • May have a steeper learning curve compared to ORM-based migration tools
  • Limited advanced features compared to some other migration tools

Code Examples

  1. Defining a migration:
package main

import (
    "database/sql"
    "github.com/rubenv/sql-migrate"
)

var migrations = &migrate.MemoryMigrationSource{
    Migrations: []*migrate.Migration{
        &migrate.Migration{
            Id:   "1",
            Up:   []string{"CREATE TABLE users (id INT, name TEXT)"},
            Down: []string{"DROP TABLE users"},
        },
    },
}
  1. Applying migrations:
db, _ := sql.Open("postgres", "postgres://user:password@localhost/dbname?sslmode=disable")
n, err := migrate.Exec(db, "postgres", migrations, migrate.Up)
if err != nil {
    // Handle error
}
fmt.Printf("Applied %d migrations!\n", n)
  1. Rolling back migrations:
n, err := migrate.Exec(db, "postgres", migrations, migrate.Down)
if err != nil {
    // Handle error
}
fmt.Printf("Rolled back %d migrations!\n", n)

Getting Started

  1. Install sql-migrate:

    go get -v github.com/rubenv/sql-migrate/...
    
  2. Create a dbconfig.yml file in your project root:

    development:
      dialect: postgres
      datasource: host=localhost dbname=myapp_development user=myuser password=mypassword sslmode=disable
      dir: migrations
    
  3. Create a migration file:

    sql-migrate new add_users_table
    
  4. Edit the generated SQL file in the migrations directory.

  5. Run the migration:

    sql-migrate up
    

Competitor Comparisons

14,958

Database migrations. CLI and Golang library.

Pros of migrate

  • Supports a wider range of databases, including NoSQL options
  • Offers CLI tool for easier integration and usage
  • Provides more flexibility with migration file formats (SQL and Go)

Cons of migrate

  • More complex setup and configuration
  • Steeper learning curve for beginners
  • Less integrated with Go's database/sql package

Code Comparison

sql-migrate:

migrations := &migrate.FileMigrationSource{
    Dir: "migrations",
}
n, err := migrate.Exec(db, "postgres", migrations, migrate.Up)

migrate:

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

Key Differences

  • sql-migrate is more focused on SQL databases and integrates well with Go's database/sql package
  • migrate offers more database options and file formats but requires additional setup
  • sql-migrate uses a simpler API, while migrate provides more advanced features and customization options

Both projects aim to simplify database migrations in Go applications, but they cater to different use cases and preferences. sql-migrate is generally easier for beginners and straightforward SQL migrations, while migrate offers more flexibility and advanced features for complex scenarios and diverse database types.

6,594

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

Pros of Goose

  • Supports multiple database drivers out of the box (PostgreSQL, MySQL, SQLite, etc.)
  • Offers both CLI and programmatic usage, providing flexibility in implementation
  • Includes a feature to generate SQL migrations from Go structs

Cons of Goose

  • Less extensive documentation compared to sql-migrate
  • Fewer configuration options for customizing migration behavior
  • Limited support for rollback operations in certain scenarios

Code Comparison

sql-migrate:

migrations := &migrate.FileMigrationSource{
    Dir: "migrations",
}
n, err := migrate.Exec(db, "mysql", migrations, migrate.Up)

Goose:

if err := goose.Up(db, "migrations"); err != nil {
    log.Fatalf("goose up: %v", err)
}

Both libraries offer straightforward ways to execute migrations, with Goose providing a slightly more concise syntax. sql-migrate allows for more explicit configuration of the migration source and database driver, while Goose simplifies the process with a single function call.

Overall, Goose offers broader database support and additional features like struct-to-SQL migration generation, making it suitable for projects requiring multi-database compatibility. sql-migrate, on the other hand, provides more detailed documentation and finer control over migration processes, which may be preferable for projects with specific migration requirements or those needing extensive customization.

5,223

🚀 A lightweight, framework-agnostic database migration tool.

Pros of dbmate

  • Language-agnostic: Works with any programming language or framework
  • Standalone binary: No need for runtime dependencies
  • Supports multiple database types (MySQL, PostgreSQL, SQLite)

Cons of dbmate

  • Less integrated with Go ecosystem compared to sql-migrate
  • Fewer advanced features like rollback hooks or custom migration types

Code Comparison

sql-migrate:

migrations := &migrate.FileMigrationSource{
    Dir: "migrations",
}
n, err := migrate.Exec(db, "mysql", migrations, migrate.Up)

dbmate:

dbmate new create_users_table
dbmate up

Key Differences

  • sql-migrate is a Go library, while dbmate is a standalone CLI tool
  • sql-migrate uses Go code for configuration, dbmate uses a database.yml file
  • dbmate supports auto-creation of databases, sql-migrate requires manual setup

Use Cases

  • sql-migrate: Better for Go projects with complex migration needs
  • dbmate: Ideal for multi-language projects or simple migration requirements

Both tools provide database migration capabilities, but cater to different development workflows and project structures. The choice between them depends on specific project needs and team preferences.

8,090

Flyway by Redgate • Database Migrations Made Easy.

Pros of Flyway

  • More comprehensive database migration tool with support for multiple databases
  • Offers both command-line and API-based migration execution
  • Provides versioning and undo capabilities for migrations

Cons of Flyway

  • Steeper learning curve due to more complex configuration options
  • Requires separate installation and setup, unlike SQL-migrate which is a Go library

Code Comparison

SQL-migrate:

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

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

Flyway:

Flyway flyway = Flyway.configure().dataSource(url, user, password).load();
flyway.migrate();

Summary

SQL-migrate is a simpler, Go-specific migration tool, while Flyway offers a more feature-rich, cross-platform solution. SQL-migrate integrates easily into Go projects, whereas Flyway provides broader database support and more advanced migration capabilities. The choice between them depends on project requirements, database complexity, and development ecosystem preferences.

Main Liquibase Source

Pros of Liquibase

  • More extensive database support, including NoSQL databases
  • Richer feature set, including rollback capabilities and preconditions
  • Larger community and more frequent updates

Cons of Liquibase

  • Steeper learning curve due to more complex configuration
  • Heavier footprint and potentially slower execution for simple projects

Code Comparison

sql-migrate:

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

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

Liquibase:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
    
    <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(50)"/>
        </createTable>
    </changeSet>
</databaseChangeLog>

sql-migrate uses a simpler Go-based approach, while Liquibase employs XML changesets for more complex scenarios.

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

sql-migrate

SQL Schema migration tool for Go. Based on gorp and goose.

Test Go Reference

Features

  • Usable as a CLI tool or as a library
  • Supports SQLite, PostgreSQL, MySQL, MSSQL and Oracle databases (through gorp)
  • Can embed migrations into your application
  • Migrations are defined with SQL for full flexibility
  • Atomic migrations
  • Up/down migrations to allow rollback
  • Supports multiple database types in one project
  • Works great with other libraries such as sqlx
  • Supported on go1.13+

Installation

To install the library and command line program, use the following:

go get -v github.com/rubenv/sql-migrate/...

For Go version from 1.18, use:

go install github.com/rubenv/sql-migrate/...@latest

Usage

As a standalone tool

$ sql-migrate --help
usage: sql-migrate [--version] [--help] <command> [<args>]

Available commands are:
    down      Undo a database migration
    new       Create a new migration
    redo      Reapply the last migration
    status    Show migration status
    up        Migrates the database to the most recent version available

Each command requires a configuration file (which defaults to dbconfig.yml, but can be specified with the -config flag). This config file should specify one or more environments:

development:
  dialect: sqlite3
  datasource: test.db
  dir: migrations/sqlite3

production:
  dialect: postgres
  datasource: dbname=myapp sslmode=disable
  dir: migrations/postgres
  table: migrations

(See more examples for different set ups here)

Also one can obtain env variables in datasource field via os.ExpandEnv embedded call for the field. This may be useful if one doesn't want to store credentials in file:

production:
  dialect: postgres
  datasource: host=prodhost dbname=proddb user=${DB_USER} password=${DB_PASSWORD} sslmode=require
  dir: migrations
  table: migrations

The table setting is optional and will default to gorp_migrations.

The environment that will be used can be specified with the -env flag (defaults to development).

Use the --help flag in combination with any of the commands to get an overview of its usage:

$ sql-migrate up --help
Usage: sql-migrate up [options] ...

  Migrates the database to the most recent version available.

Options:

  -config=dbconfig.yml   Configuration file to use.
  -env="development"     Environment.
  -limit=0               Limit the number of migrations (0 = unlimited).
  -version               Run migrate up to a specific version, eg: the version number of migration 1_initial.sql is 1.
  -dryrun                Don't apply migrations, just print them.

The new command creates a new empty migration template using the following pattern <current time>-<name>.sql.

The up command applies all available migrations. By contrast, down will only apply one migration by default. This behavior can be changed for both by using the -limit parameter, and the -version parameter. Note -version has higher priority than -limit if you try to use them both.

The redo command will unapply the last migration and reapply it. This is useful during development, when you're writing migrations.

Use the status command to see the state of the applied migrations:

$ sql-migrate status
+---------------+-----------------------------------------+
|   MIGRATION   |                 APPLIED                 |
+---------------+-----------------------------------------+
| 1_initial.sql | 2014-09-13 08:19:06.788354925 +0000 UTC |
| 2_record.sql  | no                                      |
+---------------+-----------------------------------------+

Running Test Integrations

You can see how to run setups for different setups by executing the .sh files in test-integration

# Run mysql-env.sh example (you need to be in the project root directory)

./test-integration/mysql-env.sh

MySQL Caveat

If you are using MySQL, you must append ?parseTime=true to the datasource configuration. For example:

production:
  dialect: mysql
  datasource: root@/dbname?parseTime=true
  dir: migrations/mysql
  table: migrations

See here for more information.

Oracle (oci8)

Oracle Driver is oci8, it is not pure Go code and relies on Oracle Office Client (Instant Client), more detailed information is in the oci8 repo.

Install with Oracle support

To install the library and command line program, use the following:

go get -tags oracle -v github.com/rubenv/sql-migrate/...
development:
  dialect: oci8
  datasource: user/password@localhost:1521/sid
  dir: migrations/oracle
  table: migrations

Oracle (godror)

Oracle Driver is godror, it is not pure Go code and relies on Oracle Office Client (Instant Client), more detailed information is in the godror repository.

Install with Oracle support

To install the library and command line program, use the following:

  1. Install sql-migrate
go get -tags godror -v github.com/rubenv/sql-migrate/...
  1. Download Oracle Office Client(e.g. macos, click Instant Client if you are other system)
wget https://download.oracle.com/otn_software/mac/instantclient/193000/instantclient-basic-macos.x64-19.3.0.0.0dbru.zip
  1. Configure environment variables LD_LIBRARY_PATH
export LD_LIBRARY_PATH=your_oracle_office_path/instantclient_19_3
development:
  dialect: godror
  datasource: user/password@localhost:1521/sid
  dir: migrations/oracle
  table: migrations

As a library

Import sql-migrate into your application:

import "github.com/rubenv/sql-migrate"

Set up a source of migrations, this can be from memory, from a set of files, from bindata (more on that later), or from any library that implements http.FileSystem:

// Hardcoded strings in memory:
migrations := &migrate.MemoryMigrationSource{
    Migrations: []*migrate.Migration{
        &migrate.Migration{
            Id:   "123",
            Up:   []string{"CREATE TABLE people (id int)"},
            Down: []string{"DROP TABLE people"},
        },
    },
}

// OR: Read migrations from a folder:
migrations := &migrate.FileMigrationSource{
    Dir: "db/migrations",
}

// OR: Use migrations from a packr box
// Note: Packr is no longer supported, your best option these days is [embed](https://pkg.go.dev/embed)
migrations := &migrate.PackrMigrationSource{
    Box: packr.New("migrations", "./migrations"),
}

// OR: Use pkger which implements `http.FileSystem`
migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: pkger.Dir("/db/migrations"),
}

// OR: Use migrations from bindata:
migrations := &migrate.AssetMigrationSource{
    Asset:    Asset,
    AssetDir: AssetDir,
    Dir:      "migrations",
}

// OR: Read migrations from a `http.FileSystem`
migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: httpFS,
}

Then use the Exec function to upgrade your database:

db, err := sql.Open("sqlite3", filename)
if err != nil {
    // Handle errors!
}

n, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up)
if err != nil {
    // Handle errors!
}
fmt.Printf("Applied %d migrations!\n", n)

Note that n can be greater than 0 even if there is an error: any migration that succeeded will remain applied even if a later one fails.

Check the GoDoc reference for the full documentation.

Writing migrations

Migrations are defined in SQL files, which contain a set of SQL statements. Special comments are used to distinguish up and down migrations.

-- +migrate Up
-- SQL in section 'Up' is executed when this migration is applied
CREATE TABLE people (id int);


-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back
DROP TABLE people;

You can put multiple statements in each block, as long as you end them with a semicolon (;).

You can alternatively set up a separator string that matches an entire line by setting sqlparse.LineSeparator. This can be used to imitate, for example, MS SQL Query Analyzer functionality where commands can be separated by a line with contents of GO. If sqlparse.LineSeparator is matched, it will not be included in the resulting migration scripts.

If you have complex statements which contain semicolons, use StatementBegin and StatementEnd to indicate boundaries:

-- +migrate Up
CREATE TABLE people (id int);

-- +migrate StatementBegin
CREATE OR REPLACE FUNCTION do_something()
returns void AS $$
DECLARE
  create_query text;
BEGIN
  -- Do something here
END;
$$
language plpgsql;
-- +migrate StatementEnd

-- +migrate Down
DROP FUNCTION do_something();
DROP TABLE people;

The order in which migrations are applied is defined through the filename: sql-migrate will sort migrations based on their name. It's recommended to use an increasing version number or a timestamp as the first part of the filename.

Normally each migration is run within a transaction in order to guarantee that it is fully atomic. However some SQL commands (for example creating an index concurrently in PostgreSQL) cannot be executed inside a transaction. In order to execute such a command in a migration, the migration can be run using the notransaction option:

-- +migrate Up notransaction
CREATE UNIQUE INDEX CONCURRENTLY people_unique_id_idx ON people (id);

-- +migrate Down
DROP INDEX people_unique_id_idx;

Embedding migrations with embed

If you like your Go applications self-contained (that is: a single binary): use embed to embed the migration files.

Just write your migration files as usual, as a set of SQL files in a folder.

Import the embed package into your application and point it to your migrations:

import "embed"

//go:embed migrations/*
var dbMigrations embed.FS

Use the EmbedFileSystemMigrationSource in your application to find the migrations:

migrations := migrate.EmbedFileSystemMigrationSource{
	FileSystem: dbMigrations,
	Root:       "migrations",
}

Other options such as packr or go-bindata are no longer recommended.

Embedding migrations with libraries that implement http.FileSystem

You can also embed migrations with any library that implements http.FileSystem, like vfsgen, parcello, or go-resources.

migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: httpFS,
}

Extending

Adding a new migration source means implementing MigrationSource.

type MigrationSource interface {
    FindMigrations() ([]*Migration, error)
}

The resulting slice of migrations will be executed in the given order, so it should usually be sorted by the Id field.

Usage with sqlx

This library is compatible with sqlx. When calling migrate just dereference the DB from your *sqlx.DB:

n, err := migrate.Exec(db.DB, "sqlite3", migrations, migrate.Up)
                    //   ^^^ <-- Here db is a *sqlx.DB, the db.DB field is the plain sql.DB
if err != nil {
    // Handle errors!
}

Questions or Feedback?

You can use Github Issues for feedback or questions.

License

This library is distributed under the MIT license.