Caching in Kotlin: Redis, Caffeine and Alternatives
Caching is one of the key tools for improving application performance. In Kotlin, thanks to compatibility with Java and the rich JVM ecosystem, many solutions are available: from lightweight in-memory cache to distributed systems based on Redis. In this article, we will review popular libraries, their setup, and usage examples.
Why is caching needed?
The main goals of caching:
- Reducing response time (latency) by storing frequently requested data in fast memory.
- Reducing load on databases and external APIs.
- Saving computational resources on repeated requests.
Kotlin allows using both native Java libraries and specialized Kotlin wrappers.
1. Redis via Lettuce or Redisson
Redis is the most popular in-memory data store for distributed caching. In Kotlin, it is connected via Lettuce (reactive) or Redisson (synchronous/asynchronous) clients.
Example: caching with Lettuce
// build.gradle.ktsimplementation("io.lettuce:lettuce-core:6.3.1.RELEASE")
// CacheService.ktimport io.lettuce.core.RedisClientimport io.lettuce.core.api.sync.RedisCommands
class RedisCache(private val host: String = "localhost", private val port: Int = 6379) { private val client: RedisClient = RedisClient.create("redis://$host:$port") private val connection = client.connect() private val sync: RedisCommands<String, String> = connection.sync()
fun get(key: String): String? = sync.get(key) fun set(key: String, value: String, ttlSeconds: Long = 60) { sync.setex(key, ttlSeconds, value) } fun delete(key: String) = sync.del(key) fun close() { connection.close() client.shutdown() }}
// Usagefun main() { val cache = RedisCache() cache.set("user:123", """{"name":"Alice","role":"admin"}""", 120) val data = cache.get("user:123") println(data) // {"name":"Alice","role":"admin"} cache.close()}Redisson — a higher-level API
implementation("org.redisson:redisson:3.27.2")
val config = Config().apply { useSingleServer().setAddress("redis://127.0.0.1:6379")}val redisson = Redisson.create(config)val map = redisson.getMap<String, String>("userCache")map["user:456"] = """{"name":"Bob"}"""val bob = map["user:456"]redisson.shutdown()2. Caffeine — fast in-memory cache
Caffeine is a modern replacement for Guava Cache. It is optimized for high loads and supports automatic eviction of stale entries.
implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")
import com.github.benmanes.caffeine.cache.Cacheimport com.github.benmanes.caffeine.cache.Caffeineimport java.util.concurrent.TimeUnit
val cache: Cache<String, String> = Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(10_000) .recordStats() .build()
// Write and readcache.put("key1", "value1")val value = cache.getIfPresent("key1")println(value) // value1
// Statisticsval stats = cache.stats()println("Hit rate: ${stats.hitRate()}")3. Hazelcast — distributed cache with clustering
Hazelcast is suitable for microservice architectures: the cache is automatically synchronized between nodes.
implementation("com.hazelcast:hazelcast:5.3.6")
import com.hazelcast.core.Hazelcastimport com.hazelcast.map.IMap
val instance = Hazelcast.newHazelcastInstance()val map: IMap<String, String> = instance.getMap("session-cache")map.put("session:token123", "userId=42", 30, TimeUnit.MINUTES)val userId = map.get("session:token123")instance.shutdown()4. Spring C
Also in library
Working with Dates in C# (.NET): Overview of Libraries and Built-in Tools
Generating PDF Reports in C# (.NET) with QuestPDF
Object Serialization in Kotlin: Libraries and Code Examples
Sending SMS in C# (.NET): Integration with SMS Service APIs
HTTP client for Java: overview of top libraries (Java 11, Apache, OkHttp, Retrofit)