SharedPreferences vs DataStore: Key Differences and Usage in Android
SharedPreferences is a simple API for storing small key-value pairs synchronously, while DataStore is a modern, asynchronous, and safer alternative that uses Kotlin coroutines and Flow. DataStore offers better error handling and supports both key-value and typed data storage, making it the recommended choice for new apps.Quick Comparison
Here is a quick side-by-side comparison of SharedPreferences and DataStore based on key factors.
| Factor | SharedPreferences | DataStore |
|---|---|---|
| API Type | Synchronous, callback-based | Asynchronous, coroutine and Flow-based |
| Thread Safety | Not fully thread-safe | Thread-safe by design |
| Data Format | Key-value pairs (primitive types) | Key-value pairs or typed objects (Proto DataStore) |
| Error Handling | Limited, can cause app crashes | Built-in error handling with exceptions |
| Performance | Can block main thread | Non-blocking, efficient |
| Migration | Legacy, older API | Recommended modern replacement |
Key Differences
SharedPreferences is the traditional way to store simple key-value data in Android. It works synchronously and can block the main thread if used improperly, which may cause UI lag. It also lacks robust error handling and is not fully thread-safe, so concurrent access can lead to data corruption.
On the other hand, DataStore is a newer, recommended API that uses Kotlin coroutines and Flow for asynchronous data storage. It is designed to be thread-safe and non-blocking, improving app performance and reliability. DataStore supports two implementations: Preferences DataStore for simple key-value pairs and Proto DataStore for typed objects using Protocol Buffers.
DataStore also provides better error handling by catching exceptions during data read/write operations, preventing app crashes. Overall, DataStore is more modern, safer, and scalable compared to SharedPreferences.
Code Comparison
Here is how you save and read a simple string value using SharedPreferences in Kotlin.
val sharedPreferences = context.getSharedPreferences("prefs", Context.MODE_PRIVATE) // Save data sharedPreferences.edit().putString("username", "Alice").apply() // Read data val username = sharedPreferences.getString("username", "") ?: ""
DataStore Equivalent
Here is the equivalent code using Preferences DataStore with Kotlin coroutines.
val Context.dataStore by preferencesDataStore(name = "prefs") val USERNAME_KEY = stringPreferencesKey("username") // Save data suspend fun saveUsername(context: Context, name: String) { context.dataStore.edit { prefs -> prefs[USERNAME_KEY] = name } } // Read data val usernameFlow: Flow<String> = context.dataStore.data .map { prefs -> prefs[USERNAME_KEY] ?: "" }
When to Use Which
Choose SharedPreferences if you need a quick, simple solution for very small apps or legacy projects where migration is not feasible. It is easy to use but may cause performance issues in complex apps.
Choose DataStore for modern Android apps that require safe, asynchronous, and efficient data storage. It is the recommended approach for new projects and supports advanced features like typed data and better error handling.