README ¶
Bolt
Bolt is a command-line tool designed to simplify and streamline your database migration process.
It is distributed as a standalone binary, making it easy to run anywhere without having to setup any tooling, and it is language indepenent. It doesn't matter what programming language you're using, you can use Bolt for any project you have.
Table of Contents
Features
- Schema migrations are written in plain SQL.
- Migrations can be versioned sequentially or by creation timestamp.
- All migrations run in transactions by default.
- Supports up and down migrations and jumping to any particular schema version.
- Supports PostgreSQL, MySQL, SQL Server, and SQLite3.
Installation
Go install
$ go install github.com/eugenetriguba/bolt/cmd/bolt@latest
This will install Bolt to your $GOBIN
directory. Make sure that $GOBIN
is in your $PATH
.
Homebrew
$ brew tap eugenetriguba/homebrew-bolt
$ brew install bolt
Tutorial
In this tutorial, we'll guide you through the basics of using Bolt by running through how you can create a migration, apply it, revert it, and see the status of your migrations.
Creating your first migration
Run the following command to create your first migration:
$ bolt new -m "my first migration"
Created migration 20240316145038 - my first migration.
Upon completion, a migrations directory will be created with the following structure:
migrations
└── 20240316145038_my_first_migration.sql
1 directory, 1 file
Bolt automatically creates the migrations directory and your migration scripts inside it.
Writing your migration scripts
Bolt utilizes plain SQL for migration scripts. Each migration directory contains a comment for the upgrade script portion with -- migrate:up
and a comment for the downgrade script with -- migrate:down
.
- Open up
20240316145038_my_first_migration.sql
You'll see the following template in the file for your migration:
-- migrate:up
-- migrate:down
- Write your migration script
-- migrate:up
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- migrate:down
DROP TABLE users;
Starting up a Database Container
We'll use Docker to run a PostgreSQL database container for this tutorial:
- Install Docker
If you don't have docker installed, view the installation instructions here.
- Startup the PostgreSQL container
$ docker run --name bolt-postgres -e POSTGRES_USER=bolt_user -e POSTGRES_PASSWORD=bolt_password -e POSTGRES_DB=bolt_tutorial_db -p 5432:5432 --detach postgres:16.1-alpine3.19
Configuring Bolt
Bolt can be configured with a bolt.toml
file or environment variables. For simplicity, we'll use a bolt.toml
file in this tutorial.
- Create a
bolt.toml
file:
$ touch bolt.toml
- Add the following contents to the file:
[database]
host = "localhost"
port = 5432
user = "bolt_user"
password = "bolt_password"
dbname = "bolt_tutorial_db"
driver = "postgresql"
Applying your migration
Apply your migration, which will execute the upgrade.sql
script:
$ bolt up
Applying migration 20240316145038_my_first_migration..
Successfully applied migration 20240316145038_my_first_migration!
Checking Migration Status
To view the status of your migration:
$ bolt status
Version Message Applied
20240316145038 my_first_migration X
This command displays the migration's version, name, and whether the migration was applied or not.
Verifying the Migration
Connect to the database container to confirm the users table was created:
$ docker exec -it bolt-postgres psql -U bolt_user -d bolt_tutorial_db
bolt_tutorial_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+-----------
public | bolt_migrations | table | bolt_user
public | users | table | bolt_user
(2 rows)
We can see that our users
table was created successfully. We also see another table that we didn't explicitly create called bolt_migrations
. This table is used by Bolt to keep track of which migrations have been applied to your database. You should not modify this table manually.
Downgrading Your Migration
To revert your migration:
$ bolt down
Reverting migration 20240316145038_my_first_migration..
Successfully reverted migration 20240316145038_my_first_migration!
Verifying Migration Reversion
Reconnect to the database container and check that the users table has been removed:
$ docker exec -it bolt-postgres psql -U bolt_user -d bolt_tutorial_db
bolt_tutorial_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+-----------
public | bolt_migrations | table | bolt_user
(1 row)
Next Steps
Congrats! You've learned the core features of Bolt. If you want learn more, see the How-to, Reference, or Explanation section.
How-to
How to execute a migration script without a transaction
In your migration script, add a transaction:false
option:
-- migrate:up transaction:false
-- migrate:down transaction:false
Reference
Database Compatibility
- PostgreSQL
- MySQL
- Microsoft SQL Server
- SQLite3
Configuration
There are two ways to configure Bolt: via a bolt.toml
file or via environment variables. If you use both methods, the environment variables will always take precedence.
Configuration File
Bolt attempts to find a bolt.toml
file in your current working directory
or in any parent directory.
[migrations]
# The directory where your migration scripts are located.
# Defaults to "migrations". This directory is relative to
# the current working directory. You may also use an absolute
# path.
directory_path = "migrations"
# The migration versioning style you prefer. Supported options
# are "timestamp" and "sequential". Defaults to "timestamp".
#
# Note: It is not supported to change migration version styles
# i.e. you can't have a mix of sequential and timestamp migrations.
version_style = "timestamp"
# Connection parameters for the database Bolt will be
# applying migrations to. All connection parameters are
# required.
[database]
# The host to use to connect to your database.
host =
# The port to use to connect to your database.
port =
# The user to use to connect to your database.
user =
# The password to use to connect to your database.
password =
# The name of the database within your DBMS. If you're
# using sqlite3, this is the filesystem path to the db.
dbname =
# The name of the database driver to use to connect to
# the database. Either "postgresql", "mysql", "mssql", or "sqlite3".
driver =
Environment Variables
All configuration file settings have corresponding environment variables.
BOLT_MIGRATIONS_DIR_PATH
BOLT_MIGRATIONS_VERSION_STYLE
BOLT_DB_HOST
BOLT_DB_PORT
BOLT_DB_USER
BOLT_DB_PASSWORD
BOLT_DB_NAME
BOLT_DB_DRIVER
Commands
bolt new
$ bolt help new
new [-message|-m]:
Create a new database migration
-m string
alias for -message (default "autogenerated")
-message string
Message to use for the migration (default "autogenerated")
bolt up
$ bolt help up
up [-version|-v]:
Apply migrations against the database
-v string
alias for -version
-version string
The version to upgrade up and including to.
bolt down
$ bolt help up
down [-version|-v]:
Downgrade migrations against the database
-v string
alias for -version
-version string
The version to downgrade down and including to.
bolt status
$ bolt help status
status:
List the database migrations and their statuses
bolt version
$ bolt help version
version:
Show the current version of Bolt
Script Execution Options
Bolt provides a way for you to customize how your migration scripts are executed if you need something different than the default behavior.
You can do this by adding onto the -- migrate:up
or -- migrate:down
comments with your own execution option. The options must be in the following format: -- migrate:up <option1> <option2> <...>
or -- migrate:down <option1> <option2> <...>
. The following options are available:
transaction:false
: Execute the migration script without a transaction. By default, every migration script will be attempted to be executed within a transaction, however, some SQL commands cannot be executed within a transaction so you'll need to opt out of that behavior in those cases.
Version Styles
The following version styles are supported:
- Timestamp
- Sequential
Explanation
How Are Migration Scripts Executed?
Bolt executes upgrade and downgrade migration scripts in a transaction. This ensures that if any errors occur during the execution of any migration script, the transaction will be rolled back and the migration will be marked as failed. Bolt will then exit with an error code and output what error has occurred to standard error. However, do note that some databases, like MySQL, commit certain DDL statements immediately even if you're in a transaction.
How Does Bolt Know What Migrations Have Been Applied?
Bolt keeps track of which migrations have been applied to your database by creating a table called bolt_migrations
. This table contains a single column called version
which is the version of the migration that was applied. That version is compared to the versions you have locally.
How Are Migrations Applied?
When you run bolt up
, Bolt will look at your local migration scripts and compares the version part of the migration directory names to the versions that have been inserted into the bolt_migrations
table. Any versions that aren't in the table will be applied in order, starting with the oldest migration. Applying a migration entails executing the -- migrate:up
portion of the script in a transaction and inserting in the migration's version into the bolt_migrations
table.
How Are Migrations Reverted?
When you run bolt down
, Bolt will look at the bolt_migrations
table and compare the versions to the versions of your local migration scripts. Any versions that are in the table but not in your local migration scripts will be reverted in order, starting with the newest migration. Reverting a migration entails executing the -- migrate:down
portion of the script in a transaction and removing the migration's version from the bolt_migrations
table.
What are Migration Version Styles?
Whenever you create a migration, it'll be prefixed with a "version". This is what is used by Bolt to keep track of what order to apply or revert migrations. Version styles are different supported options for what this prefix will be.
Bolt supports two different options for this:
- Sequential versions
- Timestamp versions
Sequential versions are incrementing integers. When you create a migration, it'll be prefixed with a number like "001", "002", and so on. Timestamp versions use the current time on migration creation as the prefix.
Why can't I change between version styles?
The main reason that switching back and forth between "sequential" and "timestamp" versions is not supported is because Bolt will no longer know how to properly sort your migrations in the right order (and therefore, apply or revert them in the right order). If you've been using sequential migrations, such as "001" and "002", and then move over to timestamp migrations, such as "20200101000000", Bolt won't know how to order these correctly when both exist. Furthermore, because the "version" is parsed and sorted according to the version style that is configured, the parsing will fail if a mix of version styles are used.
This means that if you wanted to switch version styles, you could do it manually by updating your local migrations to use the new version style and update the entries in bolt_migrations
to match, but there is no tooling support for doing this change.
How is the migration message used?
All migrations are created on the local filesystem in the format <version>_<message>
. Bolt uses the <version>
part of the name for keeping track of the migrations and how they should be applied or reverted. The <message>
part is purely informational so you know what that migration is for.
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
internal
|
|
configloader
Package configloader implements a Config type for loading in the configuration to be used by the app.
|
Package configloader implements a Config type for loading in the configuration to be used by the app. |