---
title: "Safe Ecto Migrations"
description: "Running migrations in production environments without accidentally causing locks or long running operations takes some care and awareness. This guide lays it all out, walks you through it, provides recipes to accomplish common tasks all while avoiding costly and embarrassing system downtime."
---

# Safe Ecto Migrations

[Annie Ruygt](https://annieruygtillustration.com/)

Fly.io runs apps close to users, by transmuting Docker containers into micro-VMs that run on our own hardware around the world. This post launches off the [Safe Ecto Migrations](https://fly.io/phoenix-files/safe-ecto-migrations/) series guide. If you just want to ship your Phoenix app, the easiest way to learn more is to [try it out](https://fly.io/speedrun/); you can be up and running in just a couple minutes.

As an Elixir developer who cares about system up-time and avoiding “scheduled maintenance” windows, and more importantly avoiding “unscheduled maintenance” windows 😉, this guide dives deep into Ecto database migrations and how they can be used safely in production systems.

This is guide comes in a 4 part series of posts. The guide helps you:

1. Understand Ecto migrations
2. Migrate and rollback the database using Mix releases
3. Avoid pitfalls during migrations

This guide includes a set of recipes for common migration scenarios. You can jump ahead to those, but it is helpful to understand what’s going on at a deeper level and to get your project setup ahead of time for running migrations in a production environment and

**Note** : This guide uses PostgreSQL and may differ if you’re using a different database. I’ll note where differences may be, but I do not go into depth on different database systems. This was also written using Ecto 3.6.x.

## Guide Table of Contents

- **Part 1:** [Anatomy of an Ecto migration](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/)
  - [Inspect SQL](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#inspect-sql)
  - [Migration Options](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#migration-options)
  - [Inspecting Locks In a Query](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#inspecting-locks-in-a-query)
  - [Safeguards in the database](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#safeguards-in-the-database)
  - [Add a lock_timeout](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#add-a-lock_timeout)
  - [Statement Timeout](https://fly.io/phoenix-files/anatomy-of-an-ecto-migration/#statement-timeout)
- **Part 2:** [How to migrate Mix Release projects](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/)
  - [Release Module](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/#release-module)
  - [Start the Release](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/#start-the-release)
  - [Check migration status](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/#check-migration-status)
  - [Run the migrations](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/#run-the-migrations)
  - [OMG ROLL IT BACK](https://fly.io/phoenix-files/how-to-migrate-mix-release-projects/#omg-roll-it-back)
- **Part 3:** [Migration Recipes](https://fly.io/phoenix-files/migration-recipes/)
  - [Adding an index](https://fly.io/phoenix-files/migration-recipes/#adding-an-index)
  - [Adding a reference or foreign key](https://fly.io/phoenix-files/migration-recipes/#adding-a-reference-or-foreign-key-constraint)
  - [Adding a column with a default value](https://fly.io/phoenix-files/migration-recipes/#adding-a-column-with-a-default-value)
  - [Changing the type of a column](https://fly.io/phoenix-files/migration-recipes/#changing-the-type-of-a-column)
  - [Removing a column](https://fly.io/phoenix-files/migration-recipes/#removing-a-column)
  - [Renaming a column](https://fly.io/phoenix-files/migration-recipes/#renaming-a-column)
  - [Renaming a table](https://fly.io/phoenix-files/migration-recipes/#renaming-a-table)
  - [Adding a check constraint](https://fly.io/phoenix-files/migration-recipes/#adding-a-check-constraint)
  - [Setting NOT NULL on an existing column](https://fly.io/phoenix-files/migration-recipes/#setting-not-null-on-an-existing-column)
  - [Adding a JSON column](https://fly.io/phoenix-files/migration-recipes/#adding-a-json-column)
  - [References](https://fly.io/phoenix-files/migration-recipes/#references)
  - [Reference Material](https://fly.io/phoenix-files/migration-recipes/#reference-material)
- **Part 4:** [Backfilling Data](https://fly.io/phoenix-files/backfilling-data/)
  - [Bad](https://fly.io/phoenix-files/backfilling-data/#bad)
  - [Good](https://fly.io/phoenix-files/backfilling-data/#good)
  - [Batching Deterministic Data](https://fly.io/phoenix-files/backfilling-data/#batching-deterministic-data)
  - [Batching Arbitrary Data](https://fly.io/phoenix-files/backfilling-data/#batching-arbitrary-data)
  - [We’re Done!](https://fly.io/phoenix-files/backfilling-data/#were-done)

## Fly ❤️ Elixir

Fly is an awesome place to run your Elixir apps. It’s really easy to get started. You can be running in minutes.

[Deploy your Elixir app today! →](https://docs.fly.io/elixir)
