🧠 Full Blog Post:
In modern Android development, storing structured data locally is crucial for offline support, caching, and smooth user experience. Room, a part of Jetpack Architecture Components, makes it easy to interact with SQLite databases using clean and maintainable Kotlin code. One of the most essential concepts you’ll use with Room is CRUD operations: Create, Read, Update, and Delete.
In this Day 19 guide, we explore practical CRUD usage with Room and build a simple example to understand how Room fits into real-world Android apps using MVVM and Kotlin Coroutines.
📦 What is CRUD?
CRUD stands for:
- Create → Insert new records into the database
- Read → Fetch data (e.g., list of items)
- Update → Modify existing data
- Delete → Remove data from the database
🏗️ Setting Up Room
Before using Room, add the dependencies in your build.gradle
:
kotlinCopyEditdependencies {
def room_version = "2.6.1"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
}
Enable Kotlin annotation processing:
kotlinCopyEditapply plugin: 'kotlin-kapt'
🧱 Step-by-Step Practical Setup
1️⃣ Define the Entity
kotlinCopyEdit@Entity(tableName = "user_table")
data class User(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String,
val email: String
)
2️⃣ Create the DAO
kotlinCopyEdit@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("SELECT * FROM user_table ORDER BY id DESC")
fun getAllUsers(): Flow<List<User>>
@Update
suspend fun updateUser(user: User)
@Delete
suspend fun deleteUser(user: User)
}
3️⃣ Setup the Room Database
kotlinCopyEdit@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Use a singleton to instantiate the database:
kotlinCopyEditobject DatabaseProvider {
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context,
AppDatabase::class.java,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
💡 Practical Example: ViewModel Usage
kotlinCopyEdit@HiltViewModel
class UserViewModel @Inject constructor(private val dao: UserDao) : ViewModel() {
val users: StateFlow<List<User>> = dao.getAllUsers()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
fun addUser(name: String, email: String) = viewModelScope.launch {
dao.insertUser(User(name = name, email = email))
}
fun deleteUser(user: User) = viewModelScope.launch {
dao.deleteUser(user)
}
}
🚀 Best Practices for Room CRUD
- Use
Flow
orLiveData
for real-time updates in UI - Handle nulls and empty lists gracefully
- Use
OnConflictStrategy.REPLACE
to avoid duplicates - Perform database operations on background threads with Coroutines

🔹 Key Points:
- What CRUD means in Room
- Setting up Room components (Entity, DAO, Database)
- Real-world usage examples of CRUD
- Kotlin Coroutines and LiveData/StateFlow usage
- Best practices for scalable database code
🎯 Conclusion
CRUD operations form the backbone of any local database interaction. With Room, Android developers can write simple, readable, and reliable code for managing app data. Whether it’s saving user profiles, todo tasks, or notes, Room combined with MVVM and Kotlin makes database operations efficient and scalable.