dbmate

repository·main·Indexed 27 days ago

https://github.com/amacneil/dbmate

A standalone database migration tool that uses plain SQL to keep schemas in sync across developers and production servers. It supports PostgreSQL, MySQL, MariaDB, SQLite, ClickHouse, BigQuery, and Spanner (PostgreSQL Dialect). dbmate provides a CLI for managing migrations, schema dumps, and database availability checks, and can also be used as a Go library with support for embedding migrations in binaries.

Tokens
4.8K
Snippets
10
Records
26
Agent score
91%

What's inside dbmate

  1. Understand dbmate core concepts

    main

    Migration Files

    Stored in ./db/migrations by default. Files are timestamp-versioned. To modify a migration that has already been applied, you should rollback the migration first, as dbmate only tracks the version number, not the file content.

    Schema File

    Written to ./db/schema.sql by default. This is a complete dump of your database schema. It should be checked into source control to allow for easy diffing and quick database restoration without running every migration sequentially.

    Schema Migrations Table

    An internal table (default name: schema_migrations) used to record which migration versions have been applied to the database.

  2. Configure the DATABASE_URL connection string

    main

    Dbmate uses the DATABASE_URL environment variable to locate your database. It automatically looks for a .env file in the current directory. If multiple environment variables are needed (e.g., for testing), you can specify a different one using the -e flag.

    Format: protocol://username:password@host:port/database_name?options

    Supported Protocols:

    • mysql
    • postgres / postgresql
    • sqlite / sqlite3
    • clickhouse
    • bigquery
    • spanner-postgres

    Note: username and password must be URL encoded if they contain special characters.

  3. Create and format migration files

    main

    Migration files are plain SQL files stored in ./db/migrations by default. They use a specific syntax to separate the 'up' (applying) and 'down' (rolling back) logic. Both directives are required in every file.

    Example file structure ([date]_create_users.sql):

    -- migrate:up
    create table users (
      id integer,
      name varchar(255),
    );
    
    -- migrate:down
    drop table if exists users;
  4. Create and write migrations

    main

    To create a new migration file, use the new command. This generates a .sql file in the db/migrations/ directory with a timestamped version prefix.

    Migration Structure: Each file contains -- migrate:up and -- migrate:down sections. You can include multiple migration blocks in a single file; the file succeeds or fails as a single unit.

  5. Run and rollback migrations

    main

    Use the following commands to manage your database schema:

    • dbmate up: Applies all pending migrations in numerical order. This command will also attempt to create the database if it doesn't exist.
    • dbmate migrate: Applies pending migrations without attempting to create the database.
    • dbmate rollback: Reverts the most recent migration (requires a -- migrate:down section in the file).

    Note: dbmate up automatically updates the ./db/schema.sql file.

    $ dbmate up
    $ dbmate rollback
  6. Wait for the database to be available

    main

    When using Docker, the database server might not be ready immediately. Use the wait command or the --wait flag to pause execution until the database is reachable.

    • dbmate wait: Blocks until the database is available (attempts every second for up to 60 seconds).
    • --wait: A flag that can be used with other commands (e.g., dbmate --wait up).
    • --wait-timeout: Customizes the timeout (default is 60s).
  7. Install dbmate

    main

    You can install dbmate using several package managers depending on your environment:

    NPM

    npm install --save-dev dbmate
    npx dbmate --help

    macOS (Homebrew)

    brew install dbmate
    dbmate --help

    Linux (Direct Binary)

    sudo curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64
    sudo chmod +x /usr/local/bin/dbmate
    /usr/local/bin/dbmate --help

    Windows (Scoop)

    scoop install dbmate
    dbmate --help

    Docker Use the image ghcr.io/amacneil/dbmate. When running migrations, use a bind mount to make your local directory available inside the container.

    # Run help
    docker run --rm -it --network=host ghcr.io/amacneil/dbmate --help
    
    # Create a new migration using a bind mount
    docker run --rm -it --network=host -v "$(pwd)/db:/db" ghcr.io/amacneil/dbmate new create_users_table
    npm install --save-dev dbmate
  8. Export the database schema

    main

    Dbmate automatically maintains a ./db/schema.sql file whenever you run up, migrate, or rollback. It is recommended to check this file into version control.

    To manually trigger a schema dump without running migrations, use the dump command. This command requires the underlying database client (e.g., pg_dump, mysqldump, or sqlite3) to be installed in your PATH.

    You can pass additional arguments directly to the underlying tool using --.

  9. Generate the dbmate NPM package without binaries

    main

    For local development, if you do not have the dbmate binaries available on your system, you can generate the package while skipping the binary copy step using the --skip-bin flag.

    npm run generate -- --skip-bin
  10. Configure the schema migrations table name

    main

    Dbmate tracks applied migrations in a table named schema_migrations. You can customize this table name using either the CLI flag or an environment variable.

    • CLI Flag: --migrations-table <name>
    • Environment Variable: DBMATE_MIGRATIONS_TABLE
  11. Configure the development environment with Docker Compose

    main

    The docker-compose.yml file defines a development environment (dev service) that orchestrates multiple database engines for testing. The dev service depends on MySQL, Postgres, ClickHouse, ClickHouse clusters, BigQuery, and Spanner emulators. It uses environment variables to provide connection URLs for these services.

    services:
      dev:
        build:
          context: .
          target: dev
        volumes:
          - .:/src
        depends_on:
          - mysql
          - postgres
          - clickhouse
          - clickhouse-cluster-01
          - clickhouse-cluster-02
          - bigquery
          - spanner-emulator
        environment:
          CLICKHOUSE_TEST_URL: clickhouse://clickhouse:9000/dbmate_test
          CLICKHOUSE_CLUSTER_01_TEST_URL: clickhouse://ch-cluster-01:9000/dbmate_test
          CLICKHOUSE_CLUSTER_02_TEST_URL: clickhouse://ch-cluster-02:9000/dbmate_test
          MYSQL_TEST_URL: mysql://root:root@mysql/dbmate_test
          POSTGRES_TEST_URL: postgres://postgres:postgres@postgres/dbmate_test?sslmode=disable
          BIGQUERY_TEST_URL: bigquery://test/us-east5/dbmate_test?disable_auth=true&endpoint=http%3A%2F%2Fbigquery%3A9050
          SPANNER_POSTGRES_TEST_URL: spanner-postgres://spanner-emulator/dbmate_test?sslmode=disable