🏠 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
}
}
}
}
@Database
defines 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 🎯
