#migration #sqlx #postgres


A very simple migration framework for sqlx and postgres

5 releases

0.0.5 Mar 12, 2021
0.0.4 Feb 5, 2021
0.0.3 Dec 31, 2020
0.0.2 Dec 11, 2020
0.0.1 Oct 10, 2020

#2143 in Database interfaces

Download history 5/week @ 2023-05-30 5/week @ 2023-06-06 1/week @ 2023-06-13 6/week @ 2023-06-20 11/week @ 2023-06-27 1/week @ 2023-07-04 9/week @ 2023-07-25 1/week @ 2023-08-01 6/week @ 2023-08-15 116/week @ 2023-08-22 24/week @ 2023-08-29 7/week @ 2023-09-05 8/week @ 2023-09-12

156 downloads per month

MIT license

202 lines


This crate is a very lightweight migration framework. It simply runs a series of sql commands in succession. It is not sophisticated.

Let's take a look at the built-in migration that the crate uses to create the table:

pub fn migration() -> Migration {
        CREATE TABLE migrations (
            name TEXT NOT NULL PRIMARY KEY,
            executed_at TIMESTAMPTZ NOT NULL DEFAULT now()
        DROP TABLE IF EXISTS migrations

Right now, it's hard coded against TIMESTAMPTZ making this crate only suitable for Postgres. @ecton is only using this crate with Postgres, but would welcome any contributions to make this more generic.

Each with_up call is executed in the order it is added to the Migration structure. When rolling back a migration, the with_down instructions are operated in reverse order. This allows you to write with_up and with_down on a single-structure basis like the example above shows, keeping the up and down logic close together.

If you're working on a migration and want it to execute every time, just add .debug() to the builder pattern before returning it. debug() is not enabled on builds without cfg(debug_assertions) ensuring that if you build with --release for deploying, you will never accidentally deploy a migration that was still marked as being debugged.

Lastly, if you want to test rebuilding the database from scratch, you can use .nuclear_debug() instead, which will force every run to undo all migrations and redo them.

The pattern for executing migrations looks like this:

pub fn migrations() -> Vec<Migration> {
        // ...

pub async fn run_all() -> Result<(), MigrationError> {
    let pool = connect_to_postgres();

    Migration::run_all(&pool, migrations()).await


~1M SLoC