← All courses

Data Storage: Preferences, DataStore & Room

🗓 May 31, 2026 ⏱ 2 min read

Choosing where to store data

Android gives you several storage options. Picking the right one matters:

  • SharedPreferences / DataStore — small key-value data (settings, flags, the logged-in user id).
  • Room (SQLite) — structured, related data you query (notes, messages, a cached list).
  • Files — images, documents, downloaded media.

SharedPreferences (simple, classic)

val prefs = getSharedPreferences("settings", MODE_PRIVATE)
prefs.edit().putBoolean("darkMode", true).apply()
val dark = prefs.getBoolean("darkMode", false)

DataStore (the modern replacement)

DataStore is the recommended way to store key-value data. It is asynchronous (won’t block the UI) and uses coroutines/Flow.

val Context.dataStore by preferencesDataStore("settings")
val DARK = booleanPreferencesKey("darkMode")

// write
context.dataStore.edit { it[DARK] = true }
// read as a Flow
val darkFlow = context.dataStore.data.map { it[DARK] ?: false }

Room: a real database

Room is Google’s database library over SQLite. You define three things: an Entity (a table), a DAO (your queries), and a Database.

@Entity
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val text: String
)

@Dao
interface NoteDao {
    @Insert suspend fun add(note: Note)
    @Delete suspend fun remove(note: Note)
    @Query("SELECT * FROM Note ORDER BY id DESC")
    fun observeAll(): Flow<List<Note>>
}

@Database(entities = [Note::class], version = 1)
abstract class AppDb : RoomDatabase() {
    abstract fun noteDao(): NoteDao
}

Using the database

val db = Room.databaseBuilder(context, AppDb::class.java, "app.db").build()
lifecycleScope.launch {
    db.noteDao().add(Note(text = "Buy milk"))
}
// observe live updates
db.noteDao().observeAll().collect { notes -> render(notes) }

Common mistakes

  • Storing big lists in SharedPreferences — use Room.
  • Running Room queries on the main thread — mark them suspend or return Flow.
  • Forgetting to bump the database version and add a migration when you change a table.
Summary: small settings → DataStore; structured/queried data → Room (with suspend/Flow); big binary files → the file system.