Page
Library
Module
Module type
Parameter
Class
Class type
Source
A database migration tool and library for OCaml, supporting PostgreSQL, MariaDB/MySQL, and SQLite. Write plain-SQL migrations with up/down sections; run them from the CLI during development, or embed the library in your app and migrate on startup.
migra generate create_users # scaffold a timestamped migration
$EDITOR migrations/*_create_users.sql
migra migrate # apply pending migrations
migra status # see what's appliedup/down sections in a single file. Full SQL is supported: dollar-quoted function bodies, DELIMITER for MySQL routines, and comments.redo.--dry-run to preview, --database-url to override the environment, --table to customise the tracking table.Migra.Migrator API.opam install migra
# plus the driver(s) you need (optional dependencies):
opam install caqti-driver-postgresql # postgresql://, postgres://
opam install caqti-driver-mariadb # mariadb://, mysql://
opam install caqti-driver-sqlite3 # sqlite3://Migra detects the database from the URL scheme:
Database | URL examples |
|---|---|
PostgreSQL |
|
MariaDB / MySQL |
|
SQLite |
|
The URL comes from --database-url or the DATABASE_URL environment variable. Percent-encode special characters in credentials (@ -> %40).
Files are named YYYYMMDDHHMMSS_description.sql and contain two sections:
-- +migrate up
CREATE TABLE users (id SERIAL PRIMARY KEY, email TEXT NOT NULL);
-- +migrate down
DROP TABLE users;For MySQL/MariaDB stored routines whose body contains semicolons, use a DELIMITER directive (as you would in the mysql client):
-- +migrate up
DELIMITER //
CREATE PROCEDURE addrow(IN n INT) BEGIN INSERT INTO t VALUES (n); END //
DELIMITER ;export DATABASE_URL="postgresql://localhost:5432/myapp"
migra generate <name> # create a new migration file
migra migrate # apply all pending migrations
migra status # show applied/pending migrations
migra rollback # roll back the most recent migration
migra redo # roll back the last migration and re-apply it
migra init # create the database
migra setup # create the database and migrate
migra drop # drop the database
migra reset # drop, recreate, and migrateCommon options: -d/--dir DIR (migrations directory, default migrations), -t/--table NAME (tracking table, default schema_migrations), -D/--database-url URL, -v/--verbose, and --dry-run (on migrate / rollback). rollback also takes --step N, --to VERSION, --all.
Use the library to run migrations programmatically - for example, on web-app startup. See examples/migrate_on_startup.ml.
let migrate () =
let config = Migra.Migrator.make ~database_url:(Sys.getenv "DATABASE_URL") () in
match Lwt_main.run (Migra.Migrator.run config) with
| Error e ->
Printf.eprintf "migration error: %s\n" (Migra.Types.show_error e); exit 1
| Ok r when not (Migra.Migrator.succeeded r) ->
Printf.eprintf "%d migration(s) failed\n" r.failure_count; exit 1
| Ok r -> Printf.printf "applied %d migration(s)\n" r.success_count
(* e.g. before Dream.run: *)
let () = migrate (); Dream.run @@ Dream.logger @@ routerThe public API is two modules:
Migra.Migrator - run, rollback, redo, status, generate, pending_plan/rollback_plan; a make config constructor; and an optional ?on_event callback for progress reporting.Migra.Database - database lifecycle (create_database, drop_database) and URL helpers.run/rollback return Error only when migrations could not be run at all (bad URL, connection failure, drift); a migration whose SQL fails surfaces as Ok with failure_count > 0 - check Migra.Migrator.succeeded.
migrate re-validates applied migrations first and refuses to run if a file was modified after being applied, has gone missing, or a new migration is older than the latest applied one.dune build
dune fmt # format (ocamlformat)
dune runtest # unit tests (no database needed)
# Integration tests need running databases; docker-compose.yml brings them up:
docker compose up -d --wait
DATABASE_URL=postgresql://postgres@localhost:5433/postgres \
MARIADB_URL=mariadb://root:root@127.0.0.1:3307/mysql \
dune exec test/test_integration.exe
docker compose downSee docs/ for troubleshooting and running the tests.
MIT - see LICENSE.