Room Database Migrations: Evolving Your Schema Safely

A Room migration is a renovation plan for your database. When you change your schema, you provide SQL instructions to upgrade existing user data without loss, preventing crashes on app updates. The footgun is forgetting to increment the database version.
WHY IT EXISTS Apps evolve, and so does their data. When you need to change your database schema—add a column, rename a table—you can't just change your code. Existing users have the old database structure on their devices. An app update with a new schema would cause a crash on launch. Migrations provide a formal way to update a user's database from an old version to a new one, preserving their data.
THE MENTAL MODEL Think of migrations as a set of explicit instructions for upgrading your database from one version to the next. You define a path from version 1 to 2, from 2 to 3, and so on. When a user updates your app, Room checks the database version on their device against the version in your new code. If they don't match, Room looks for a migration path and executes the SQL commands you've provided to bring the database up to date.
HOW IT WORKS Anytime you alter an @Entity or other part of your database schema, you must increment the version number in your @Database annotation. Then, you provide one or more Migration objects to your database builder. Each migration object defines the SQL statements needed to get from a specific start version to an end version. For simple changes like adding a column, Room also offers automatic migrations where you just declare the versions, and Room generates the necessary SQL itself.
WHEN TO USE IT Use migrations every time you change the database schema for an app that is in production. Use manual migrations for complex changes like renaming a column, splitting a table, or transforming data during the update. Use automatic migrations for simple, additive changes like adding a new column or table, as they require less boilerplate code.
WHEN NOT TO USE IT During very early development, when the schema is in constant flux and there is no user data to preserve, it's often easier to use fallbackToDestructiveMigration(). This tells Room to simply wipe the database and recreate it if a migration is needed. This should never be used in a production app, as it will delete all of the user's local data.
ONE CANONICAL EXAMPLE Imagine adding a last_name column to a User table. First, in your @Database class, you'd change version = 1 to version = 2. Then you'd define the migration: val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE User ADD COLUMN last_name TEXT") } }. Finally, you add this to your database builder: Room.databaseBuilder(...).addMigrations(MIGRATION_1_2).build().
Read the original → developer.android.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.