Storage SPI
Underneath the public API sits a minimal interface that makes the storage engine swappable — this is how it's built, not something a consumer of the library implements or configures directly.
internal interface Storage {
fun getBytes(key: String): ByteArray?
fun putBytes(key: String, value: ByteArray)
fun remove(key: String)
fun contains(key: String): Boolean
fun keys(prefix: String): List<String>
}
Every decomposed field key (see Field Decomposition) is read and written through exactly these five operations. Two implementations exist:
MmkvStorage— wraps a real Tencent MMKV instance. Used in production on both Android and iOS.InMemoryStorage— wraps a plain in-memory map, guarded for concurrent access. BacksDocuments.inMemory(), used for unit tests with no real MMKV instance involved — see Collections & Testing.
Everything above this interface — the public API, field decomposition, serialization,
reactivity — lives in commonMain and has no idea which Storage
implementation it's talking to. Only the concrete implementation is platform-specific, which is
what keeps the entire public surface KMP-clean. See
Shared KMP Persistence and
Platform Support.