Answers · Deploying

How do I roll back a bad deploy without losing data?

Run kamal rollback to boot the previous image, which is still on the server. It takes seconds because nothing is rebuilt or pulled. Your code goes back; your database does not. A deploy that ran a destructive migration cannot be undone this way, which is why additive migrations matter more than the rollback command.

The command

bin/kamal app containers          # find the previous version tag
bin/kamal rollback <version>
curl -sI https://yourdomain.com/up | head -1

kamal app containers lists what is on the host, including stopped containers from previous releases. The version is the git SHA the image was built from, and the image name it matches comes from config/deploy.yml.

What rolls back and what does not

Your application code rolls back completely. The container is the unit, so gems, assets and configuration all return to the previous state together.

Your data does not. The SQLite file lives on a mounted volume precisely so that it survives container swaps, which is the behavior you want every day except this one. If the bad deploy ran a migration that dropped a column or rewrote rows, rolling the code back leaves the old code looking at a schema it does not expect.

Write migrations that can be rolled back

This is the real answer, and it is a habit rather than a command. Split anything destructive into two deploys:

  1. Deploy one: add the new column, write to both, read from the old one. Nothing is removed.
  2. Deploy two: read from the new column, then remove the old one, once deploy one has been live long enough that you would not roll back past it.

Between those two deploys, kamal rollback is safe, because the schema supports both versions of the code. This is the only reliable way to keep a rollback honest, and it costs one extra deploy.

Check what the migration actually did

bin/kamal app exec 'bin/rails db:migrate:status' | tail -20

That lists which migrations have run on the server, which is the thing to look at before deciding whether a rollback is enough or whether you need to write a corrective migration instead. Compare it against db/schema.rb in the commit you are rolling back to: if the two disagree about a column, the rollback needs a migration in front of it.

Related questions

How do I deploy a Rails 8 app without Heroku?

Use Kamal, which ships with Rails 8. You give it a server over SSH and a container registry in config/deploy.yml, run kamal setup once, and kamal deploy after that. It builds an image, pushes it, and swaps containers with no downtime. A $5 VPS replaces the PaaS.

How do I deploy a Rails app from GitHub Actions?

Run kamal deploy as a workflow step. Kamal needs three things in the runner: an SSH key that can reach the server, registry credentials, and RAILS_MASTER_KEY. All three go in as repository secrets and are read by .kamal/secrets. Gate the deploy job behind the test job so a red build never ships.

How do I fix no space left on device on a deploy server?

Old container images are the cause, not your app. Every deploy pushes a new image and the server keeps the old ones. Run docker image prune -a -f to reclaim the space, then check with df -h. On a 25GB VPS this usually returns several gigabytes, and it is worth doing before you are locked out rather than after.