How can I safely roll back a Gleam schema change using the built‑in migration feature?
0 reputation · 15 Feb 2025, 06:03 UTC
0 reputation · 15 Feb 2025, 06:03 UTC
When using Gleam’s migration feature to alter a database schema—for example, adding a new column to an existing table—I need a reliable way to revert that change if the migration fails or produces unexpected results.
The rollback must preserve existing data, be idempotent so it can be run multiple times, and ideally run inside a transaction that can be aborted without leaving the database in an inconsistent state.
What specific statements should I include in the down migration to guarantee data integrity? How can I automate rollback testing in a CI pipeline without affecting production data? Are there Gleam‑provided helpers or patterns that wrap migrations in a safely abortable transaction?
26525 reputation · 15 Feb 2025, 15:24 UTC
To guarantee data integrity when you need to revert a schema change in Gleam, write the down function so that it is idempotent, wrapped in a transaction, and performs only the minimal reversible operations. Then, in CI, run the rollback against a brand‑new database instance and verify that the application still passes its tests. Gleam itself does not ship a dedicated “transaction helper” – you have to use the database’s transaction syntax inside the migration file.
migrations/xxxx_description.gleam and contains two functions:pub fn up() { … }
pub fn down() { … }down function. For a column addition, use an IF EXISTS guard and wrap the change in a transaction.pub fn down() {
// Begin a transaction – most DB drivers used by Gleam support it.
run_sql("BEGIN;");
run_sql("ALTER TABLE users DROP COLUMN IF EXISTS new_column;");
run_sql("COMMIT;");
}
Using IF EXISTS makes the statement safe to run multiple times and BEGIN/COMMIT guarantees that the operation can be rolled back if the migration fails partway.
down code may no longer match the original state. Compare the file against the commit that originally ran the migration.gleam migrate downor target a specific revision:gleam migrate down 20230915120000 The CLI will locate the last applied migration (or the one you specify) and execute its down function.gleam migrate status shows one fewer applied migration and that the schema_migrations table reflects the expected revision.In a CI pipeline, you can validate that a rollback works without touching production data by following this pattern:
gleam migrate up to bring the schema to the latest state.gleam migrate down and then gleam migrate status to ensure the revision count has decreased.Because the database is freshly created for each job, the rollback cannot affect real data. You can use a --dry-run flag if your database driver supports it to preview the SQL without applying it.
BEGIN; and COMMIT; inside the migration file as shown above.IF EXISTS / IF NOT EXISTS in DDL statements. For example, ALTER TABLE … ADD COLUMN … IF NOT EXISTS in up and DROP COLUMN IF EXISTS in down.gleam migrate down on a staging environment to confirm that the rollback will succeed before the new migration is applied to production.If your application uses a database other than PostgreSQL (e.g., MySQL, SQLite), the exact DDL syntax may differ. Let us know your DB engine so we can tailor the down statements accordingly.
Use comments to ask for clarification. Post a solution as an answer.
1,660 reputation · 15 Feb 2025, 10:41 UTC
One premise worth correcting: Gleam's core toolchain (compiler, CLI, stdlib) ships no built-in migration feature, so there is no gleam migrate down command to rely on. Schema migrations in Gleam projects come from community libraries (e.g., cigogne, which applies timestamped SQL files and can roll back the last applied migration) or external tools like sqlx-cli, Flyway, or dbmate. Rollback must be performed with whichever tool applied the migration — check that tool's docs for its exact command and semantics, since the ecosystem is young and details change.
Two tool-agnostic points: first, transactional rollback is only guaranteed on databases with transactional DDL (PostgreSQL yes; MySQL/MariaDB implicitly commits around DDL), so verify your target before trusting atomicity. Second, dropping a column in a down migration destroys data irreversibly — an expand-and-contract pattern (deploy backward-compatible changes first, remove old structures later) is safer than relying on down migrations in production. Test any down migration against a restored production backup before trusting it.