Skip to content

Multiplatform Settings

Developer UtilitiesUtilities/ConfigurationKotlin

What it is

A Kotlin Multiplatform key-value storage library wrapping SharedPreferences on Android, NSUserDefaults on Apple platforms and equivalents elsewhere.

Settings exposes typed get and put methods. Platform-specific construction happens once, behind expect/actual, and shared code uses the interface.

Installation

implementation("com.russhwolf:multiplatform-settings:1.2.0")

Getting started

The smallest useful thing you can do with it, and what each part means.

Shared preference access
// commonMain
expect fun createSettings(): Settings

class Preferences(private val settings: Settings) {
    var theme: String
        get() = settings.getString("theme", "system")
        set(value) = settings.putString("theme", value)

    var onboarded: Boolean
        get() = settings.getBoolean("onboarded", false)
        set(value) = settings.putBoolean("onboarded", value)
}

// androidMain
actual fun createSettings(): Settings =
    SharedPreferencesSettings(context.getSharedPreferences("app", MODE_PRIVATE))

// iosMain
actual fun createSettings(): Settings = NSUserDefaultsSettings(NSUserDefaults.standardUserDefaults)
The shared Preferences class is the only thing the rest of the app sees, so adding a setting means touching one file rather than one per platform.

Advanced usage

Where the library earns its place over a simpler alternative.

Delegates and observing changes
class Preferences(settings: Settings) {
    // Property delegates remove the getter/setter boilerplate.
    var theme: String by settings.string("theme", defaultValue = "system")
    var fontScale: Float by settings.float("font_scale", 1.0f)
    var lastSync: Long? by settings.nullableLong("last_sync")
}

// Observe as a Flow (requires the coroutines artifact and an
// ObservableSettings implementation).
@OptIn(ExperimentalSettingsApi::class)
val themeFlow: Flow<String> =
    (settings as ObservableSettings).getStringFlow("theme", "system")
This is for small values only — preferences, flags, a token. It is not a database, and storing a large JSON blob here will be slow and is not what the underlying platform APIs are for.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Values do not persist on iOS
NSUserDefaults writes asynchronously. It is normally fine, but call synchronize() before an expected termination in tests.
Flow APIs will not compile
They are experimental and need @OptIn(ExperimentalSettingsApi::class) plus the coroutines artifact.

Best practices

  • Wrap Settings in a typed class rather than scattering string keys through the codebase.
  • Use property delegates to remove getter and setter boilerplate.
  • Store only small values; use SQLDelight or a file for anything larger.
  • Never store secrets here — use the platform keychain or EncryptedSharedPreferences.

Background

Why it exists, and what it was reacting to.

Every platform has its own small-preferences API with a different name. This library gives shared code one interface so settings logic need not be written per target.