Room Database Setup in Android Applications
Room is ORM wrapper over SQLite from Google, part of Jetpack. Removes boilerplate of manual SQLiteOpenHelper writing, adds compile-time SQL query checking, and properly works with coroutines and Flow. Room setup is standard task for any Android app with local storage: cache server data, offline mode, history, drafts.
What Setup Includes
Three components: Entity (table), DAO (query interface), Database (entry point, RoomDatabase subclass). Build via KSP (Kotlin Symbol Processing) — faster than KAPT, current Google recommendation from Room 2.5+.
@Entity with @PrimaryKey(autoGenerate = true), @ColumnInfo for column renaming, @Embedded for nested objects, @Relation for One-to-Many and Many-to-Many via @Junction. TypeConverter for custom types — LocalDate, Instant, enums, JSON fields.
DAO interface: @Query, @Insert(onConflict = OnConflictStrategy.REPLACE), @Update, @Delete. Return types: suspend fun for one-time operations, Flow<List<T>> for reactive queries auto-reemitting on table changes.
@Dao
interface ArticleDao {
@Query("SELECT * FROM articles WHERE categoryId = :id ORDER BY publishedAt DESC")
fun getByCategory(id: Long): Flow<List<Article>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(articles: List<Article>)
@Transaction
@Query("SELECT * FROM articles WHERE id = :id")
suspend fun getWithComments(id: Long): ArticleWithComments
}
@Transaction on queries returning objects with @Relation is mandatory, otherwise data may be inconsistent on parallel operations.
Schema Migrations
fallbackToDestructiveMigration() fits development only — in production it's data loss. Right way: addMigrations(MIGRATION_1_2, MIGRATION_2_3) with explicit SQL for each schema change. Room exports JSON schema (room.schemaLocation in build.gradle) — must commit to repo and test migrations via MigrationTestHelper.
Migration test:
migrationTestHelper.runMigrationsAndValidate(
TEST_DB, 3, true, MIGRATION_1_2, MIGRATION_2_3
)
Without migration tests, first schema change release crashes for some users on app open.
Common Errors
Room queries on main thread. By default Room throws exception. allowMainThreadQueries() in builder — tests only, never production.
Single Database instance. RoomDatabase is expensive, create once via synchronized singleton or via Hilt with @Singleton. Multiple instances in parallel coroutines — potential race condition.
Flow and lifecycle. Flow<T> from Room has no Android specifics — must collect in viewModelScope with repeatOnLifecycle, not lifecycleScope directly, otherwise collection continues in background.
Setup Room with basic schema, DAO, migrations, unit tests: 2-3 days. Complex schemas with many relationships and Full-Text Search via @Fts4 — up to 5 days. Cost estimated individually.







