Getting Started

Add Cache to your project and start caching in three lines.

1. Add the dependency

In your build.gradle.kts:

dependencies {
    implementation("io.peekandpoke.ultra:cache:0.107.2")
}

Find the latest version on Maven Central.

Cache is a Kotlin Multiplatform library — it works in commonMain, jvmMain, jsMain, and nativeMain (linuxX64, linuxArm64, macosX64, macosArm64, mingwX64).

2. Create a cache

Use the fastCache builder to create a cache with the eviction policies you need:

import io.peekandpoke.ultra.cache.fastCache
import kotlin.time.Duration.Companion.minutes

val cache = fastCache<String, String> {
    expireAfterAccess(10.minutes)
    maxEntries(1000)
}

3. Use it

// Put a value
cache.put("greeting", "Hello, World!")

// Get a value
val value = cache.get("greeting")  // "Hello, World!"

// Get-or-put — the most common pattern
val user = cache.getOrPut("user:42") {
    // Only called on cache miss
    database.findUser("42")
}

// Check existence
cache.has("greeting")  // true

// Remove
cache.remove("greeting")

// Clear everything
cache.clear()

The Cache interface

All caches implement the Cache<K, V> interface:

Method Returns Behavior
get(key) V? Returns the value or null if not present
put(key, value) Unit Stores a value, replacing any existing entry
remove(key) V? Removes and returns the value, or null
has(key) Boolean Checks if a key exists
getOrPut(key) { ... } V Returns existing or computes and stores a new value
clear() Unit Removes all entries
size Int Number of entries
keys Set<K> Snapshot of current keys
values List<V> Snapshot of current values
entries Map<K, V> Immutable snapshot of all entries

Thread safety

All operations on FastCache are synchronized internally. You can safely call get(), put(), and getOrPut() from multiple coroutines or threads without external locking.

The cache uses a coroutine-based background loop for eviction processing. Eviction doesn't happen on the calling thread — it's deferred to the loop, which runs every 50ms by default.

Builder methods that return a handle

Most builder methods return the builder itself (for chaining). One exception: statistics() returns a StatisticsBehaviour handle that you hold onto to call snapshot() later:

lateinit var stats: FastCache.StatisticsBehaviour<String, String>

val cache = fastCache<String, String> {
    expireAfterAccess(10.minutes)
    stats = statistics()  // returns the handle, not the builder
}

// Later...
val snapshot = stats.snapshot()
println(snapshot.hitRate)

See Observability for full details on statistics.