Local Persistence with Room

Room is Android's official persistence library — a type-safe, compile-time-checked layer over SQLite that turns annotated Kotlin classes into a real relational database without the boilerplate.

Learn Local Persistence with Room in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end you'll define an @Entity , write a reactive @Dao , and wire up a RoomDatabase .

What You'll Learn in This Lesson

1️⃣ Defining a Table with @Entity

An @Entity turns a data class into a table: each instance is a row, each property a column. Mark one property with @PrimaryKey , optionally with autoGenerate = true so Room assigns IDs.

Room reads these annotations at compile time and generates the matching SQLite schema for you.

2️⃣ Querying with a @Dao

A @Dao interface declares your data access. Use @Query for custom SQL, plus @Insert / @Update / @Delete . Return a Flow for reactive reads, and mark writes suspend .

Because observeAll() returns a Flow , your UI refreshes itself whenever the data changes — no polling required.

3️⃣ The @Database Class

The @Database class extends RoomDatabase , lists every entity and a version, and exposes abstract DAO getters. Build a single instance with Room.databaseBuilder .

Model a Task entity, a reactive DAO, and a database that exposes it.

📋 Quick Reference — Room

Practice quiz

What annotation marks a class as a Room database table?

  • @Entity
  • @Model
  • @Persist
  • @Table

Answer: @Entity. @Entity marks a data class as a table; each instance is a row and each property a column.

Which library does Room sit on top of?

  • Realm
  • A custom NoSQL engine
  • SQLite
  • Firebase

Answer: SQLite. Room is an abstraction layer over Android's built-in SQLite, removing boilerplate while keeping full SQL access.

What annotation marks an interface that defines database access methods?

  • @Repository
  • @Dao
  • @Access
  • @Query

Answer: @Dao. A Data Access Object (@Dao) declares the methods used to read and write data.

Which annotation lets you write a custom SELECT statement in a DAO?

  • @Sql
  • @Select
  • @Fetch
  • @Query

Answer: @Query. @Query holds an arbitrary SQL statement; Room validates it at compile time.

How do you define the primary key for an entity?

  • With @PrimaryKey on a property
  • By naming a property 'id'
  • Room picks one automatically with no annotation
  • With the @Key annotation on the class

Answer: With @PrimaryKey on a property. @PrimaryKey marks the property; add autoGenerate = true to let Room assign incrementing IDs.

Why return a Flow from a Room @Query?

  • It encrypts the rows
  • It makes the query observable, re-emitting when the underlying data changes
  • It runs the query on the main thread
  • It compresses the result

Answer: It makes the query observable, re-emitting when the underlying data changes. A Flow-returning query is reactive: Room re-emits a fresh result whenever the table's data changes.

Why should insert/update/delete DAO methods usually be 'suspend' functions?

  • Because Room requires it for compilation
  • To make them faster than SQL
  • So they return a Flow automatically
  • So they run off the main thread without blocking the UI

Answer: So they run off the main thread without blocking the UI. Marking write methods suspend lets you call them from coroutines so disk I/O never blocks the UI thread.

What class must your database class extend, annotated with @Database?

  • DatabaseHelper
  • ContentProvider
  • RoomDatabase
  • SQLiteOpenHelper

Answer: RoomDatabase. The @Database-annotated abstract class extends RoomDatabase and exposes abstract DAO getters.

What is a Room migration used for?

  • Moving the app to a new device
  • Defining how to upgrade the schema from one version to the next
  • Copying data to the cloud
  • Switching from SQLite to MySQL

Answer: Defining how to upgrade the schema from one version to the next. A Migration tells Room the SQL needed to evolve the schema when the database version increases, preserving user data.

What does a @TypeConverter let Room do?

  • Store a custom type (like Date) by converting it to and from a type SQLite supports
  • Convert Kotlin to Java
  • Encrypt a column
  • Convert between SQL dialects

Answer: Store a custom type (like Date) by converting it to and from a type SQLite supports. A @TypeConverter maps an unsupported type (such as Date or an enum) to a primitive SQLite can store, and back.