
Unified, type-safe key-value and object storage with KType-based serialization, annotation-driven validation, powerful query DSL, and optional KSP code generation for type-safe query builders and validators.
KMP DataStore is a Kotlin Multiplatform library that wraps Jetpack DataStore to provide a unified, type-safe API for storage across Android, iOS, and Desktop.
Int, String, Boolean, etc.) and fully typesafe object storage.KotlinxDataStoreSerializer provided).filterByValue<T> and queryValues<T>().@SafeSerializable, @DataStoreKey, @RequiresSerializer and validation annotations.kotlinx.serialization being optional.kmp-datastore is available on Maven Central. No authentication required!
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
// build.gradle.kts (for Kotlin Multiplatform)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.parkwoocheol:kmp-datastore:<version>")
// Optional: for Kotlinx Serialization support
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
}
}
}
// build.gradle.kts (for Android/JVM)
dependencies {
implementation("io.github.parkwoocheol:kmp-datastore:<version>")
}For modern projects using Gradle version catalogs:
[versions]
kmpDatastore = "<version>"
[libraries]
kmp-datastore = { module = "io.github.parkwoocheol:kmp-datastore", version.ref = "kmpDatastore" }
kmp-datastore-annotations = { module = "io.github.parkwoocheol:kmp-datastore-annotations", version.ref = "kmpDatastore" }
kmp-datastore-ksp = { module = "io.github.parkwoocheol:kmp-datastore-ksp", version.ref = "kmpDatastore" }Then use it in your build.gradle.kts:
dependencies {
implementation(libs.kmp.datastore)
}dependencies {
implementation("io.github.parkwoocheol:kmp-datastore-annotations:<version>")
}plugins {
id("com.google.devtools.ksp") version "2.2.0-2.0.2"
}
dependencies {
ksp("io.github.parkwoocheol:kmp-datastore-ksp:<version>")
}// Create a DataStore instance
// For primitive types only:
val dataStore = TypeSafeDataStore("user_prefs")
// For object support with Kotlinx Serialization:
val serializer = KotlinxDataStoreSerializer()
val objectDataStore = TypeSafeDataStore("app_data", serializer)// Write
dataStore.putString("user_name", "Alice")
dataStore.putInt("login_count", 42)
// Read
dataStore.getString("user_name").collect { name ->
println("User: $name")
}@Serializable
data class UserProfile(val name: String, val age: Int)
// Write
objectDataStore.put("profile", UserProfile("Alice", 30))
// Read
objectDataStore.get<UserProfile>("profile").collect { profile ->
println("Profile: $profile")
}// Mark a class as safe for serialization with version tracking
@SafeSerializable(version = 2, description = "User profile data")
@Serializable
data class User(
@DataStoreKey("user_name", required = true)
val name: String,
val age: Int
)// Generate type-safe query builder
@DataStoreIndex(properties = ["age", "email"])
@Serializable
data class User(
val name: String,
@Min(0) @Max(150) val age: Int,
@Pattern("[a-z]+@[a-z]+\\.[a-z]+") val email: String
)
// Generated usage:
val adults = dataStore.queryUser()
.whereAgeBetween(18, 65)
.first()
// Generated validator:
val result = UserValidator.validate(user)
if (result.isFailure) {
println(result.getErrorMessages())
}// Value-based filtering
dataStore.filterByValue<Int> { key, value ->
value > 18
}.collect { keys ->
println("Adult user keys: $keys")
}
// Key + value query builder
dataStore.queryValues<String>()
.startsWith("user_")
.valueContains("john")
.sortByValueAscending()
.take(10)
.executeMap()
.collect { results ->
println("Top results: $results")
}Note: Key + value queries scan all keys and load each value. Prefer key-only queries when performance matters.
The library includes a comprehensive test suite with 68+ unit tests covering:
Run tests:
./gradlew :kmp-datastore:testFor more detailed information, check out the Documentation:
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License - see the LICENSE file for details.
KMP DataStore is a Kotlin Multiplatform library that wraps Jetpack DataStore to provide a unified, type-safe API for storage across Android, iOS, and Desktop.
Int, String, Boolean, etc.) and fully typesafe object storage.KotlinxDataStoreSerializer provided).filterByValue<T> and queryValues<T>().@SafeSerializable, @DataStoreKey, @RequiresSerializer and validation annotations.kotlinx.serialization being optional.kmp-datastore is available on Maven Central. No authentication required!
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
// build.gradle.kts (for Kotlin Multiplatform)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.parkwoocheol:kmp-datastore:<version>")
// Optional: for Kotlinx Serialization support
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
}
}
}
// build.gradle.kts (for Android/JVM)
dependencies {
implementation("io.github.parkwoocheol:kmp-datastore:<version>")
}For modern projects using Gradle version catalogs:
[versions]
kmpDatastore = "<version>"
[libraries]
kmp-datastore = { module = "io.github.parkwoocheol:kmp-datastore", version.ref = "kmpDatastore" }
kmp-datastore-annotations = { module = "io.github.parkwoocheol:kmp-datastore-annotations", version.ref = "kmpDatastore" }
kmp-datastore-ksp = { module = "io.github.parkwoocheol:kmp-datastore-ksp", version.ref = "kmpDatastore" }Then use it in your build.gradle.kts:
dependencies {
implementation(libs.kmp.datastore)
}dependencies {
implementation("io.github.parkwoocheol:kmp-datastore-annotations:<version>")
}plugins {
id("com.google.devtools.ksp") version "2.2.0-2.0.2"
}
dependencies {
ksp("io.github.parkwoocheol:kmp-datastore-ksp:<version>")
}// Create a DataStore instance
// For primitive types only:
val dataStore = TypeSafeDataStore("user_prefs")
// For object support with Kotlinx Serialization:
val serializer = KotlinxDataStoreSerializer()
val objectDataStore = TypeSafeDataStore("app_data", serializer)// Write
dataStore.putString("user_name", "Alice")
dataStore.putInt("login_count", 42)
// Read
dataStore.getString("user_name").collect { name ->
println("User: $name")
}@Serializable
data class UserProfile(val name: String, val age: Int)
// Write
objectDataStore.put("profile", UserProfile("Alice", 30))
// Read
objectDataStore.get<UserProfile>("profile").collect { profile ->
println("Profile: $profile")
}// Mark a class as safe for serialization with version tracking
@SafeSerializable(version = 2, description = "User profile data")
@Serializable
data class User(
@DataStoreKey("user_name", required = true)
val name: String,
val age: Int
)// Generate type-safe query builder
@DataStoreIndex(properties = ["age", "email"])
@Serializable
data class User(
val name: String,
@Min(0) @Max(150) val age: Int,
@Pattern("[a-z]+@[a-z]+\\.[a-z]+") val email: String
)
// Generated usage:
val adults = dataStore.queryUser()
.whereAgeBetween(18, 65)
.first()
// Generated validator:
val result = UserValidator.validate(user)
if (result.isFailure) {
println(result.getErrorMessages())
}// Value-based filtering
dataStore.filterByValue<Int> { key, value ->
value > 18
}.collect { keys ->
println("Adult user keys: $keys")
}
// Key + value query builder
dataStore.queryValues<String>()
.startsWith("user_")
.valueContains("john")
.sortByValueAscending()
.take(10)
.executeMap()
.collect { results ->
println("Top results: $results")
}Note: Key + value queries scan all keys and load each value. Prefer key-only queries when performance matters.
The library includes a comprehensive test suite with 68+ unit tests covering:
Run tests:
./gradlew :kmp-datastore:testFor more detailed information, check out the Documentation:
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
This project is licensed under the MIT License - see the LICENSE file for details.