Local Persistence with Room

Room is the recommended SQLite library for Android. You define entities, DAOs, and a database; Room generates the boilerplate at compile time.

Room uses an annotation processor (KSP). It is shown here as focused, idiomatic code you can drop into a project. The CI example app uses an in-memory repository to stay buildable without the extra toolchain — see the Examples notes.

Setup

// build.gradle.kts
plugins {
    id("com.google.devtools.ksp")
}
dependencies {
    implementation("androidx.room:room-runtime:2.6.1")
    implementation("androidx.room:room-ktx:2.6.1")   // coroutines/Flow support
    ksp("androidx.room:room-compiler:2.6.1")
}

Entity

@Entity(tableName = "articles")
data class ArticleEntity(
    @PrimaryKey val id: Int,
    val title: String,
    val body: String,
)

DAO

A DAO declares queries. Returning a Flow makes them observable — the UI updates automatically when the table changes:

@Dao
interface ArticleDao {
    @Query("SELECT * FROM articles ORDER BY id")
    fun observeAll(): Flow<List<ArticleEntity>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun upsert(article: ArticleEntity)

    @Query("DELETE FROM articles")
    suspend fun clear()
}

Database

@Database(entities = [ArticleEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun articleDao(): ArticleDao
}

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

Using it in the data layer

The repository maps entities to domain models, hiding Room from the rest of the app:

class LocalArticleRepository(private val dao: ArticleDao) : ArticleRepository {
    override fun articlesFlow(): Flow<List<Article>> =
        dao.observeAll().map { rows -> rows.map { Article(it.id, it.title, it.body) } }

    override suspend fun articles(): List<Article> = articlesFlow().first()
}

Migrations

When the schema changes, bump version and provide a Migration, or use fallbackToDestructiveMigration() during early development. Export the schema for tested migrations with the Room schema directory.

Exercises

  1. Add an isRead: Boolean column to ArticleEntity and a query for unread articles.

  2. Add a @Query that returns a single article by id as a Flow<ArticleEntity?>.


Previous: ViewModel & State Management · Next: Networking


Back to top

Kotlin & Android Programming Guide is not affiliated with JetBrains or Google. Content is provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.