DataStore for Kotlin: Complete Guide with Examples
\n\n1. What It Is and Why You Need It
\n\nDataStore is a library from Google for storing small amounts of data in Kotlin (and Android) applications. It replaces the outdated SharedPreferences and offers a safer, asynchronous, and type-safe way to work with data. DataStore uses Kotlin Coroutines and Flow, making it an ideal choice for modern applications written using reactive programming.
Why do you need DataStore? The main problem with SharedPreferences is synchronous reading from disk, which can block the UI thread, as well as the lack of data type support (everything is stored as Set<String>). DataStore solves these problems: all read and write operations are asynchronous, and data is stored in typed objects (via Protocol Buffers or Preferences). Additionally, DataStore automatically handles serialization errors and provides a clean API for working with data.
The library comes in two variants: Preferences DataStore (for storing simple key-value pairs, like in SharedPreferences) and Proto DataStore (for storing typed objects via Protocol Buffers). In this article, we will focus on Preferences DataStore as the simplest and most commonly used variant.
\n\n2. Installation
\n\nDataStore is distributed via Maven Central. To add it to a Kotlin/Android project, add the dependency to the build.gradle.kts file (app module):
dependencies {\n // Preferences DataStore\n implementation("androidx.datastore:datastore-preferences:1.1.1")\n \n // If you are using Proto DataStore\n // implementation("androidx.datastore:datastore-core:1.1.1")\n \n // For Coroutines support (usually already in the project)\n implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")\n}\n\n\nIf you are using Gradle with Groovy (build.gradle), the line will look like this:
implementation 'androidx.datastore:datastore-preferences:1.1.1'\n\n\nAfter syncing Gradle, the library is ready to use.
\n\n3. Quick Start — Minimal Working Example
\n\nLet's create a simple DataStore for storing a username and a counter.
\n\nimport android.content.Context\nimport androidx.datastore.core.DataStore\nimport androidx.datastore.preferences.core.Preferences\nimport androidx.datastore.preferences.core.edit\nimport androidx.datastore.preferences.core.intPreferencesKey\nimport androidx.datastore.preferences.core.stringPreferencesKey\nimport androidx.datastore.preferences.preferencesDataStore\nimport kotlinx.coroutines.flow.Flow\nimport kotlinx.coroutines.flow.map\n\n// Extension for Context, creating a DataStore\nval Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_settings")\n\n// Keys for data\nval USER_NAME_KEY = stringPreferencesKey("user_name")\nval COUNTER_KEY = intPreferencesKey("counter")\n\nclass UserPreferences(private val context: Context) {\n\n // Reading username as Flow\n val userName: Flow<String?> = context.dataStore.data.map { preferences ->\n preferences[USER_NAME_KEY]\n }\n\n // Reading counter as Flow\n val counter: Flow<Int> = context.dataStore.data.map { preferences ->\n preferences[COUNTER_KEY] ?: 0\n }\n\n // Saving username\n suspend fun saveUserName(name: String) {\n context.dataStore.edit { preferences ->\n preferences[USER_NAME_KEY] = name\n }\n }\n\n // Incrementing counter\n suspend fun incrementCounter() {\n context.dataStore.edit { preferences ->\n val currentCounter = preferences[COUNTER_KEY] ?: