Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungLINQ GroupBy: The Operator Everyone Uses Wrong(23.09.2026 um 09:41 Uhr)
Sichere ProgrammierungIT Heard About the Acquisition Nine Days Before It Closed(23.09.2026 um 09:45 Uhr)
Sichere ProgrammierungThe Story Behind Building NuvyntraLabs(23.09.2026 um 09:45 Uhr)
Sichere ProgrammierungFive dashboards nobody was opening(23.09.2026 um 09:46 Uhr)
Sichere ProgrammierungThe Shift from AI Insights to AI Actions in Finance(23.09.2026 um 09:47 Uhr)
Sichere ProgrammierungGo WebAssembly Meets WebForms Core 2.1(23.09.2026 um 09:49 Uhr)
Sichere ProgrammierungJust One More Round: Scope Creep in the Age of AI Agents(23.09.2026 um 09:50 Uhr)
Sichere ProgrammierungThe Calls That Reach Us Now Are the Ones the Model Could Not Answer(23.09.2026 um 09:50 Uhr)
Sichere ProgrammierungOne Loop Made Four Hundred Round Trips(23.09.2026 um 09:52 Uhr)
Sichere ProgrammierungThe order was committed and nothing else ever heard about it(23.09.2026 um 09:53 Uhr)
Sichere ProgrammierungLINQ GroupBy: The Operator Everyone Uses Wrong(23.09.2026 um 09:41 Uhr)
Sichere ProgrammierungIT Heard About the Acquisition Nine Days Before It Closed(23.09.2026 um 09:45 Uhr)
Sichere ProgrammierungThe Story Behind Building NuvyntraLabs(23.09.2026 um 09:45 Uhr)
Sichere ProgrammierungFive dashboards nobody was opening(23.09.2026 um 09:46 Uhr)
Sichere ProgrammierungThe Shift from AI Insights to AI Actions in Finance(23.09.2026 um 09:47 Uhr)
Sichere ProgrammierungGo WebAssembly Meets WebForms Core 2.1(23.09.2026 um 09:49 Uhr)
Sichere ProgrammierungJust One More Round: Scope Creep in the Age of AI Agents(23.09.2026 um 09:50 Uhr)
Sichere ProgrammierungThe Calls That Reach Us Now Are the Ones the Model Could Not Answer(23.09.2026 um 09:50 Uhr)
Sichere ProgrammierungOne Loop Made Four Hundred Round Trips(23.09.2026 um 09:52 Uhr)
Sichere ProgrammierungThe order was committed and nothing else ever heard about it(23.09.2026 um 09:53 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Room Database Migrations: Changing Your Schema Without Losing User Data

Introduction Room Database is Android's abstraction layer over SQLite, providing compile-time checked SQL queries and reactive data flow. As your app evolves, your database schema will inevitably change: adding new columns, changing data…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Introduction



Room Database is Android's abstraction layer over SQLite, providing compile-time checked SQL queries and reactive data flow. As your app evolves, your database schema will inevitably change: adding new columns, changing data types, removing obsolete fields. This is where migrations come in.



Database migrations are one of the trickiest parts of app development. Mishandled migrations can corrupt user data, cause app crashes in production, or result in data loss. In this guide, we'll explore Room's migration system, from basic column additions to advanced schema changes, and how to test them properly.






Why Database Migrations Matter



When you release your app to production and users install it, their local databases are in a specific state defined by your app's schema. When you push an update with schema changes, Room needs to know how to transform the old database to the new one without losing user data.



Consider this scenario:





  • Version 1 of your app: Users table has id and name columns


  • Version 2 of your app: You want to add an email column



If you simply change your Entity definition, Room will see the schema mismatch and throw a crash on app startup. Without a migration, users can't upgrade your app. With a migration, their existing data stays intact while the schema evolves.






The Room Entity and Schema Version



Let's start with the basics. Every Room database has a schema version number:




@Database(
entities = [User::class],
version = 1,
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}






When you update your schema, increment the version number. Room uses this number to determine which migrations to apply:




@Database(
entities = [User::class],
version = 2, // Updated from 1 to 2
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}






Important: Always set exportSchema = true. This generates JSON schema files in your build/ directory, which you should commit to version control. These serve as documentation and help you write accurate migrations.






Writing Your First Migration



A migration is a class that extends Migration and implements the upgrade logic:




val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
// Add new email column with default value
database.execSQL(
"ALTER TABLE User ADD COLUMN email TEXT NOT NULL DEFAULT ''"
)
}
}






You then add this migration to your database instance:




val db = Room.databaseBuilder(
context,
AppDatabase::class.java,
"myapp.db"
)
.addMigrations(MIGRATION_1_2)
.build()






Room will apply migrations automatically in order. When a user upgrades from version 1 to version 2, Room detects the schema mismatch, finds that a migration exists from 1→2, and applies it.






Common Migration Patterns






Adding a Column



The simplest migration:




val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"ALTER TABLE User ADD COLUMN phone TEXT DEFAULT NULL"
)
}
}






SQLite's ALTER TABLE is limited, but adding columns is always safe. Provide a DEFAULT value or allow NULL to avoid issues with existing rows.






Renaming a Column



SQLite's ALTER TABLE RENAME COLUMN was added in SQLite 3.25 (Room 2.1+). Older versions require a workaround:




val MIGRATION_3_4 = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
// Create new table with renamed column
database.execSQL("CREATE TABLE User_new (id INTEGER PRIMARY KEY, name TEXT, email_address TEXT)")
// Copy data
database.execSQL("INSERT INTO User_new SELECT id, name, email FROM User")
// Drop old table and rename
database.execSQL("DROP TABLE User")
database.execSQL("ALTER TABLE User_new RENAME TO User")
}
}









Removing a Column



Also requires the table recreation pattern:




val MIGRATION_4_5 = object : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE User_new (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
database.execSQL("INSERT INTO User_new SELECT id, name, email FROM User")
database.execSQL("DROP TABLE User")
database.execSQL("ALTER TABLE User_new RENAME TO User")
}
}









Adding a Foreign Key Constraint






val MIGRATION_5_6 = object : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE Address (id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, street TEXT, FOREIGN KEY(user_id) REFERENCES User(id))")
}
}









Destructive Migrations



A destructive migration loses data. Examples:




  • Removing a column with important data

  • Truncating a table

  • Changing a column's data type (often requires recreating the table with conversion logic)



Room does NOT apply destructive migrations by default, throwing an error instead:




Schema is not a valid Room database. The following problems were detected:
Migration didn't properly handle...






If you're certain a destructive migration is acceptable (perhaps for development or a feature where data loss is acceptable), enable it:




val db = Room.databaseBuilder(
context,
AppDatabase::class.java,
"myapp.db"
)
.addMigrations(MIGRATION_5_6)
.fallbackToDestructiveMigrationOnDowngrade() // Beware!
.build()






Warning: Never ship this to production without careful consideration. Users will lose data.






Automatic Migrations (Room 2.4+)



Room 2.4 introduced automatic migrations, which generate migration code for simple schema changes like adding columns:




@Database(
entities = [User::class],
version = 3,
autoMigrations = [
AutoMigration(from = 2, to = 3)
]
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}






For complex changes, you can specify spec classes:




class MIGRATION_2_3 : AutoMigrationSpec {
override fun onPostMigrate(database: SupportSQLiteDatabase) {
// Custom logic after auto-generated SQL
database.execSQL("UPDATE User SET updated_at = datetime('now')")
}
}

@Database(
entities = [User::class],
version = 3,
autoMigrations = [
AutoMigration(from = 2, to = 3, spec = MIGRATION_2_3::class)
]
)
abstract class AppDatabase : RoomDatabase() { }






Automatic migrations reduce boilerplate but only work for non-destructive changes.






Testing Migrations



Always test migrations before shipping:




@RunWith(AndroidJUnit4::class)
class MigrationTest {
private lateinit var testHelper: MigrationTestHelper

@get:Rule
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java.canonicalName,
FrameworkSQLiteOpenHelperFactory()
)

@Test
fun testMigrationFrom1To2() {
// Create v1 database
var db = helper.createDatabase(TEST_DB_NAME, 1)
db.execSQL("INSERT INTO User VALUES (1, 'Alice')")
db.close()

// Run migration
db = helper.runMigrationsAndValidate(
TEST_DB_NAME,
2,
validateDroppedTables = true,
MIGRATION_1_2
)

// Verify results
val cursor = db.query("SELECT * FROM User WHERE id = 1")
cursor.moveToFirst()
assert(cursor.getString(1) == "Alice") // Name preserved
assert(cursor.isNull(2)) // Email is NULL
db.close()
}
}






This test:




  1. Creates a v1 database with test data

  2. Applies the migration to v2

  3. Validates the schema matches your entities

  4. Verifies data integrity






Best Practices




  1. Version your schema: Always increment version when changing entities. Never skip versions.


  2. Provide sensible defaults: When adding columns, use DEFAULT values to avoid NULL issues.


  3. Test all migrations: Use MigrationTestHelper for every migration path. Test edge cases.


  4. Commit schema JSON files: Check in schemas/ directory so you can generate migrations from diffs.


  5. Chain migrations carefully: If jumping from v1 to v5, Room applies v1→2, v2→3, v3→4, v4→5 in order. Ensure they're backward compatible.


  6. Document schema changes: Add comments explaining why a migration exists and what it does.


  7. Avoid destructive changes in production: If you must remove a column, handle it gracefully. Consider deprecation periods.


  8. Use transactions: Room applies all migrations in a transaction. If one fails, the entire set rolls back.







Conclusion



Database migrations are essential for shipping app updates with schema changes. Room provides a robust migration system through explicit Migration classes and (in 2.4+) automatic migrations. By testing migrations thoroughly and following best practices, you can evolve your app's data model confidently.






My 8 templates use Room with migration-ready schemas. https://myougatheax.gumroad.com

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Room Database Migrations: Changing Your Schema Without Losing User Data

Thematisch verwandte Begriffe: Room, Database, Migrations, Changing · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96258 | A vulnerability has been found in onSite internet GmbH Auktion NG Auktio…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick