Room is Google’s recommended persistence library — it wraps SQLite with compile-time-verified SQL and generates boilerplate for you.

Entity — a table definition

@Entity(tableName = "notes")
data class NoteEntity(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val title: String,
    val body: String,
    val createdAt: Long = System.currentTimeMillis()
)

DAO — Data Access Object, defining your queries

@Dao
interface NoteDao {
    @Query("SELECT * FROM notes ORDER BY createdAt DESC")
    fun getAllNotes(): Flow<List<NoteEntity>>

    @Insert
    suspend fun insertNote(note: NoteEntity)

    @Delete
    suspend fun deleteNote(note: NoteEntity)

    @Query("SELECT * FROM notes WHERE id = :noteId")
    suspend fun getNoteById(noteId: Int): NoteEntity?
}

Room verifies your @Query SQL against the entity schema at compile time — a typo in a column name fails the build, not a user’s runtime.

Returning Flow<List<NoteEntity>> from a query means the UI automatically receives new emissions whenever the underlying table changes — no manual refresh logic needed.