androidengineers.Book a session

Architecture & Data

Room Database Fundamentals

article50 minHard

Room is Android's recommended library for local SQLite persistence. It lets you store structured data with compile-time checks and Kotlin-friendly APIs.

Use Room when data should remain available after the app closes, such as saved notes, offline tasks, cached lessons, or user preferences that need querying.

Entity

An entity represents a database table.

@Entity(tableName = "tasks")
data class TaskEntity(
    @PrimaryKey val id: String,
    val title: String,
    val completed: Boolean
)

DAO

A DAO defines database operations.

@Dao
interface TaskDao {
    @Query("SELECT * FROM tasks")
    fun observeTasks(): Flow<List<TaskEntity>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun upsert(task: TaskEntity)

    @Delete
    suspend fun delete(task: TaskEntity)
}

Use Flow when the UI should update automatically as database data changes.

Database

@Database(
    entities = [TaskEntity::class],
    version = 1
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun taskDao(): TaskDao
}

Create the database once, usually through dependency injection.

Migrations

Every time you change the database schema — adding a column, renaming a table, changing a type — you must increment the version number and provide a migration.

If you do not, Room will throw an exception at startup on devices that have an older version of the database.

@Database(
    entities = [TaskEntity::class],
    version = 2
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun taskDao(): TaskDao
}

val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE tasks ADD COLUMN priority INTEGER NOT NULL DEFAULT 0")
    }
}

Register the migration when building the database:

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

During development, you can use fallbackToDestructiveMigration() to wipe and recreate the database instead of writing a migration. Never use this in production — it deletes all user data.

Entity Vs Domain Model

In simple apps, you may use entities directly. In larger apps, map database entities to domain models so database details do not leak everywhere.

fun TaskEntity.toTask() = Task(id, title, completed)

Practice

Create a NoteEntity, NoteDao, and AppDatabase. Add queries to insert notes, observe all notes, and delete a note.

Summary

Room gives Android apps reliable local storage. Learn entities, DAOs, databases, suspend functions, Flow queries, and migrations. Every schema change needs a version bump and a migration — skip it in development with fallbackToDestructiveMigration, but always write real migrations before shipping to users.

YOUR LEARNING JOURNEY

0 of 22 available lessons completed

Progress saved in this browser. No account needed.
Room Database Fundamentals | Junior Android Developer | Android Engineers