Developing after mix ecto.dump

Space scene with horizon and fly balloons.
Image by Annie Ruygt

We’re Fly.io. We run apps for our users on hardware we host around the world. This post is about how to continue development after you’ve run mix ecto.dump and deleted old migration files. Fly.io happens to be a great place to run Phoenix applications. Check out how to get started!

Problem

At some point, you or your team decided to cut the dead weight of many old migrations and instead run mix ecto.dump and generate a priv/repo/structure.sql file.

Now you want to bootstrap a new staging server, dev environment, or just get setup with a clean database. You have a chicken-and-the-egg problem. Your app can’t boot without some initial DB schema and it doesn’t have the old migrations to do that. Also, you can’t IEx into your running app to execute the SQL because it can’t run without the schema.

Looking for a solution when deploying to a clean database in a production-like environment? Check out this post!

This is the problem we need to solve: How do we continue development an app that relies on a structure.sql file generated from mix ecto.dump and we are missing older migrations?

Solution

Thankfully the problem is easy to fix, but the solution isn’t obvious.

Assuming the mix ecto.dump command was used, we have a priv/repo/structure.sql file generated for us. That file should be committed to our version control system.

Next, we’ll update our project’s mix.exs file and tweak the ecto.setup task. It probably looks something like this: (Reformatted for readability)

defp aliases do
  [
    # ...
    "ecto.setup": [
      "ecto.create",
      "ecto.migrate",
      "run priv/repo/seeds.exs"
    ],
    "ecto.reset": ["ecto.drop", "ecto.setup"],
    # ...
  ]
end

The alias we care about is ecto.setup.

We’ll add a step between "ecto.create" and "ecto.migrate". We want to call mix ecto.load. However, we’ll use a couple of the flags to make it safely continue when it detects our schema is already loaded.

The command we want is ecto.load --skip-if-loaded --quiet. After updating , it should look like this:

"ecto.setup": ["ecto.create", "ecto.load --skip-if-loaded --quiet", "ecto.migrate", "run apps/core/priv/repo/seeds.exs"],

Now when we develop or test against a clean DB, it creates the DB, loads the priv/repo/structure.sql file into our database, then runs any additional migrations needed before continuing on.

Awesome! We’ve got a slick solution! Problem solved.

Do you need to solve deploying to a clean database in a production-like environment? Check out this post!

Fly.io ❤️ Elixir

Fly.io is a great way to run your Phoenix LiveView app close to your users. It’s really easy to get started. You can be running in minutes.

Deploy a Phoenix app today!