π Room Database in Jetpack Compose — Full Practical Guide (2025)
If you’re learning Android development with Jetpack Compose, one of the most important things you’ll need is a local data storage system that works even without the internet.
That’s where Room Database comes in — a powerful, efficient, and Kotlin-friendly way to manage local structured data built on top of SQLite.
π§© What is Room Database?
Room is an object-mapping layer over SQLite. It converts Kotlin data classes into database tables and vice versa — making data persistence simple and type-safe.
In simple terms: Room = SQLite made easy + Kotlin-friendly + lifecycle-aware.
✅ Common Use-Cases:
- Notes or To-Do apps
- Offline caching (store API data locally)
- User preferences or game scores
- Saving login info or user history
π§ Why Use Room Instead of SQLite?
Before Room, developers used raw SQL queries and SQLiteOpenHelper classes, which were:
- Hard to maintain
- Error-prone
- Not type-safe
Room solves these issues by offering:
- Compile-time verification of SQL queries
- Automatic mapping between Kotlin objects and tables
- Integration with Coroutines, Flow, LiveData, ViewModel
- Much less boilerplate code
π§± Core Components of Room Database (Theory)
Room follows MVVM + Repository architecture. It has three key components:
| Component | Description |
|---|---|
| Entity | Defines the structure of the database table. |
| DAO | Data Access Object — defines SQL operations like insert, delete, query. |
| Database | Main class that connects Entities and DAOs. |
1️⃣ Entity — Defining the Table
@Entity(tableName = "notes")
data class NoteEntity(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val title: String,
val content: String
)
@Entity→ Marks the data class as a table.@PrimaryKey(autoGenerate = true)→ Auto-increment ID.- Each property → A column in the table.
2️⃣ DAO — Data Access Object
@Dao
interface NoteDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(note: NoteEntity)
@Query("SELECT * FROM notes ORDER BY id DESC")
fun getAllNotes(): Flow<List<NoteEntity>>
@Delete
suspend fun delete(note: NoteEntity)
}
- @Insert → Add data.
- @Query → Fetch data with SQL.
- @Delete → Remove specific note.
Flow<List<NoteEntity>>→ Real-time data updates for Compose.
3️⃣ Database — Connecting Everything
@Database(entities = [NoteEntity::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null
fun getInstance(context: Context): NoteDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDatabase::class.java,
"note_db"
).build()
INSTANCE = instance
instance
}
}
}
}
@Databasedefines entities & version.- Singleton pattern ensures one database instance.
Room.databaseBuilder()creates the DB.
π§° Repository Layer (Clean Architecture)
class NoteRepository(private val dao: NoteDao) {
val allNotes = dao.getAllNotes()
suspend fun insert(note: NoteEntity) = dao.insert(note)
suspend fun delete(note: NoteEntity) = dao.delete(note)
}
This layer manages all data operations and ensures your app remains scalable.
π§ ViewModel Integration
class NoteViewModel(application: Application) : AndroidViewModel(application) {
private val dao = NoteDatabase.getInstance(application).noteDao()
private val repository = NoteRepository(dao)
val notes = repository.allNotes.asLiveData()
fun addNote(title: String, content: String) {
viewModelScope.launch {
repository.insert(NoteEntity(title = title, content = content))
}
}
fun delete(note: NoteEntity) {
viewModelScope.launch {
repository.delete(note)
}
}
}
viewModelScope.launch→ Background thread for safe DB ops.asLiveData()→ Converts Flow to LiveData.- ViewModel survives configuration changes.
π¨ Jetpack Compose UI (Practical Implementation)
@Composable
fun NotesScreen(viewModel: NoteViewModel = viewModel()) {
val notes by viewModel.notes.observeAsState(emptyList())
var title by remember { mutableStateOf("") }
var content by remember { mutableStateOf("") }
Column(Modifier.padding(16.dp)) {
Text("Room Database Demo", style = MaterialTheme.typography.headlineMedium)
Spacer(Modifier.height(8.dp))
OutlinedTextField(value = title, onValueChange = { title = it }, label = { Text("Title") })
OutlinedTextField(value = content, onValueChange = { content = it }, label = { Text("Content") })
Button(onClick = {
if (title.isNotBlank() && content.isNotBlank()) {
viewModel.addNote(title, content)
title = ""
content = ""
}
}, modifier = Modifier.padding(top = 8.dp)) {
Text("Add Note")
}
Spacer(Modifier.height(16.dp))
LazyColumn {
items(notes) { note ->
Card(Modifier.fillMaxWidth().padding(vertical = 4.dp)) {
Column(Modifier.padding(8.dp)) {
Text(note.title, style = MaterialTheme.typography.titleMedium)
Text(note.content, style = MaterialTheme.typography.bodyMedium)
TextButton(onClick = { viewModel.delete(note) }) {
Text("Delete")
}
}
}
}
}
}
}
✅ How it works:
- User adds a note → stored in Room DB
- Flow emits updated data automatically
- Compose UI refreshes instantly
π Full Data Flow Diagram
User Input → Compose UI → ViewModel → Repository → Room DAO → SQLite Table
↑
| (Flow)
└─── Real-time updates back to UI
⚡ Advanced Topics (Deep Knowledge)
- TypeConverters — store complex data like lists or dates.
- Migrations — handle DB structure changes safely.
- Room + Retrofit — cache API responses locally.
- Testing — use in-memory DB for unit testing.
- Coroutines & Flow — real-time updates without manual refresh.
π§ Summary Table
| Layer | Role | Example |
|---|---|---|
| Entity | Defines table structure | NoteEntity |
| DAO | Database operations | NoteDao |
| Database | Room instance | NoteDatabase |
| Repository | Manages data access | NoteRepository |
| ViewModel | Holds UI data | NoteViewModel |
| Compose UI | Displays data | NotesScreen |
π Final Thoughts
Room Database is essential for modern Android apps — not just for saving data, but for creating stable, offline-capable, and reactive apps.
Combined with Jetpack Compose, Coroutines, and Flow, it gives you a clean, scalable, and future-proof architecture.
Once you master this, you can build full-fledged apps like:
- π Notes or To-Do apps
- π° Expense trackers
- πΆ Offline caching systems
Build. Learn. Repeat. You’re now ready to create your first offline-ready app using Room + Jetpack Compose π―
