Chapter 9 of 14

Before the Scary Migration

Every developer has run a migration they were not sure about and felt the small cold moment afterwards. This chapter removes it, in two commands, and explains why this particular feature could only come from the thing that installed your database.

The problem

A destructive migration cannot be undone by migrate:rollback. The down() method restores the schema; it cannot restore the column you dropped, because the data went with it. And in local development the data is often worth more than it sounds: three weeks of hand-made test cases covering the edge conditions you had to reason about, which a fresh seed does not contain.

So people do one of two things. They avoid the experiment — writing the migration defensively, never trying the cleaner schema — or they run it and lose an afternoon rebuilding fixtures. Both are the same tax, paid differently.

The hard way

You can do this yourself: mysqldump to a file, remember where you put it, remember the flags, restore with the inverse command, remember which of the four dumps in your Downloads folder was the right one. It works, and the number of people who actually do it before every risky migration is approximately zero, because the ceremony is longer than the migration.

Two commands

grove db snapshot --db myapp --note "before migrate"
# ...run the scary migration...
grove db list
grove db restore <id>

Data restored exactly as it was. The note is not decoration — a week later, grove db list with five snapshots in it is unreadable without one.

Snapshots live under Grove's own directory rather than in your project, which keeps a database dump out of your repository and out of your build context. MySQL and PostgreSQL snapshots are plain SQL dumps — readable, greppable, restorable by hand if you ever want to. An ElyraSQL snapshot is a hot, consistent copy of its single database file, taken while it serves.

Why only a supervisor can do this

This is the chapter that makes the argument for the whole course, so it is worth stating directly.

A tool that merely connects to your database can dump it. Only a tool that owns it knows which engine is running, on which port, with which credentials, for which project — without being told, every time, by you. Grove installed the database, so grove db snapshot needs no connection string: it already knows.

That is the same property that made grove env correct in chapter 6 and per-site PHP routing possible in chapter 5. Each is small on its own. Together they are the difference between a collection of tools and an environment.

Make it a habit

Snapshot before a migration you have not run before. Snapshot before running someone else's migration on your data. Snapshot before migrate:fresh --seed on a database you have been building up by hand.

It costs seconds and it changes what you are willing to try — which is the real benefit. The best version of a schema is usually the third one you attempt, and you only get to the third if the first two were cheap.

This is also what makes an agent safe to let near your database. If you have a coding agent running migrations, a snapshot beforehand turns “what did it just do” from a question into a command. Chapter 14 comes back to this.

What you learned

  • down() restores the schema, not the data. Hand-made local fixtures are worth more than they sound.
  • Two commands, with a note, because five unlabelled snapshots are as good as none.
  • Snapshots live in Grove's directory, not in your repository or your build context.
  • Owning the database is what makes it one command — the same property behind grove env and per-site PHP.
  • Cheap experiments change what you attempt. The best schema is usually the third one.
Next: in Chapter 10 the thing you cannot build from separate tools: the full timeline of a request, the queries it caused, and a replay button.