Documents

Typed, reactive documents on top of MMKV — fast and a joy to write. Define a data class, treat it as a document, and get typed reads, copy-style updates, and Flow reactivity — all riding on the fastest key-value engine on mobile.

@Serializable
data class Note(val title: String = "", val body: String = "", val done: Boolean = false)

val note = Documents.document<Note>("note-1") // one call, you have a document

note.set(Note(title = "Pick up milk", body = "2%, not whole"))
note.update(Note::done, true) // one field, no read
note.update { current -> // several fields, one atomic write
    current.copy(
        title = "Pick up oat milk",
        body = "The barista-approved kind",
    )
}
note.flow().collect { editor.render(it) } // the editor reacts to every write

Built for elegancy

MMKV is ridiculously fast — memory-mapped, protobuf-backed, about as quick as anything else on the platform. But out of the box it hands you a bare cupboard: raw keys, primitives only. Every typed object means hand-rolling serialization and key management again, from scratch, every time. The typed and reactive alternatives buy their comfort back by giving up that speed, so you end up picking a side — fast, or pleasant to use.

Documents refuses to pick a side. It's built for elegancy: a clean, idiomatic Kotlin surface — typed documents, property delegates, a copy()-style update DSL, Flow reactivity — sitting directly on top of MMKV, costing you a little CPU for serialization and never a single extra byte of I/O. Clean code on top, MMKV all the way down.

The problem

Android and Kotlin Multiplatform apps constantly need to persist a single record of structured data — a logged-in user, a settings object, a session, a draft — and none of the usual tools fit that shape well. SharedPreferences is key-value only, awkward for nested objects, and loads the whole file into memory. Jetpack DataStore is typed, but Proto demands schema files and Preferences is still flat key-value — heavy ceremony just to store one object. SQLite and Room are relational and table-oriented, overkill for a single document with no relations to speak of. And raw MMKV is blisteringly fast but offers no abstraction at all: you're on your own for serialization and key management. There was no library giving a document-oriented, typed, reactive API with MMKV's performance underneath — so Documents is that intersection.

What it gives you

Single-process only

Every store — the default store, every named collection, and the in-memory test backend alike — is single-process. Concurrent access to the same store from more than one OS process is not supported and can corrupt it. A background service, an app extension, a second process spawned for any reason — none of these may open the same store as your main process at the same time.

This is not a soft caveat or an edge case to work around: if your app needs to share a store across processes, this library is not the right fit for that store today. Design around a single-process owner for each store, or keep multi-process data out of Documents entirely.

Built by

Where to next