A lightweight, embeddable Redis-compatible server written in Kotlin. Perfect for testing, development, and scenarios where you need an in-memory Redis instance without installing Redis itself.
✅ Redis Protocol Compatible - Implements RESP2 protocol
✅ Embedded & Lightweight - Run Redis in-process, no external dependencies
✅ Spring Boot Integration - Auto-configuration support for Spring Boot applications (via a SmartLifecycle adapter; core server is Spring-free)
✅ Easy to Use - Simple API for standalone applications
✅ Fast - Kotlin coroutines for concurrent operations
✅ Testing Friendly - Perfect for unit and integration tests
✅ Graceful Connections - QUIT command supported; client disconnects handled cleanly
- Connection:
PING,ECHO,HELLO,QUIT,COMMAND COUNT - Key-Value:
SET,GET,DEL,EXISTS - Legacy:
SETNX,SETEX(rejects non‑positive TTLs) - Hash:
HSET,HSETNX,HGET,HMGET,HINCRBY - Lists:
LPUSH,RPUSH,LPOP,RPOP,LLEN,LMOVE,LRANGE,LTRIM - Options: Expiration (
EX,PX), Conditional Sets (NX,XX)
-
RESP responses are aligned with Redis semantics:
- Status replies are used for control responses (e.g., +PONG, +OK)
- Bulk strings are used for data payloads (GET/ECHO/HGET/HMGET), including null bulk for missing values
-
On invalid RESP framing (malformed protocol), the server closes the connection to avoid stream desynchronization and preserve pipelining guarantees.
-
The server implements RESP2 and explicitly supports the QUIT command. After replying +OK, the server closes the client socket.
-
EOF, connection reset, and broken pipe from clients are treated as normal disconnects and are not logged as errors.
-
The server binds explicitly to the configured host and port:
- host=127.0.0.1 or ::1 limits access to the local machine only.
- host=0.0.0.0 (default for standalone) listens on all interfaces.
- In Spring Boot, the default host is localhost unless overridden via properties.
-
The server implements RESP2 and explicitly supports the QUIT command. After replying +OK, the server closes the client socket.
-
EOF, connection reset, and broken pipe from clients are treated as normal disconnects and are not logged as errors.
-
The server binds explicitly to the configured host and port:
- host=127.0.0.1 or ::1 limits access to the local machine only.
- host=0.0.0.0 (default for standalone) listens on all interfaces.
- In Spring Boot, the default host is localhost unless overridden via properties.
dependencies {
implementation 'io.github.sudouser777:embedded-redis-server:0.0.3'
}<dependency>
<groupId>io.github.sudouser777</groupId>
<artifactId>embedded-redis-server</artifactId>
<version>0.0.3</version>
</dependency>import io.github.embeddedredis.RedisServer
fun main() {
// Create and start the server
val server = RedisServer(port = 6379, host = "localhost")
server.start()
// Server is now running and accepting connections
println("Redis server started on port 6379")
// Add shutdown hook
Runtime.getRuntime().addShutdownHook(Thread {
server.stop()
})
// Keep the application running
Thread.currentThread().join()
}Spring support is provided via a SmartLifecycle adapter bean, keeping the core RedisServer free of Spring dependencies. The adapter starts/stops the server with the application lifecycle.
Add the embedded-redis-server dependency to your Spring Boot project.
Add configuration to your application.yml or application.properties:
application.yml:
embedded:
redis:
enabled: true # Enable/disable embedded Redis (default: true)
port: 6379 # Redis port (default: 6379)
host: localhost # Bind address (default: localhost)
auto-start: true # Auto-start on app startup (default: true)application.properties:
embedded.redis.enabled=true
embedded.redis.port=6379
embedded.redis.host=localhost
embedded.redis.auto-start=trueThe embedded Redis server will automatically start when your Spring Boot application starts (if embedded.redis.auto-start=true). Under the hood, a RedisServer bean is created and a RedisServerLifecycleAdapter manages its lifecycle.
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}@Service
class MyService {
fun useRedis() {
// Use any Redis client (Jedis, Lettuce, etc.)
val jedis = Jedis("localhost", 6379)
jedis.set("key", "value")
val value = jedis.get("key")
jedis.close()
}
}class MyRedisTest {
companion object {
private lateinit var server: RedisServer
@BeforeAll
@JvmStatic
fun startServer() {
server = RedisServer(port = 16379) // Use different port for tests
server.start()
}
@AfterAll
@JvmStatic
fun stopServer() {
server.stop()
}
}
@Test
fun testRedisOperations() {
val jedis = Jedis("localhost", 16379)
jedis.set("test", "value")
val result = jedis.get("test")
assertEquals("value", result)
jedis.close()
}
}@SpringBootTest
@TestPropertySource(properties = [
"embedded.redis.enabled=true",
"embedded.redis.port=16379"
])
class MySpringBootTest {
@Autowired
private lateinit var redisServer: RedisServer
@Test
fun testWithEmbeddedRedis() {
val jedis = Jedis("localhost", 16379)
jedis.set("spring", "boot")
val result = jedis.get("spring")
assertEquals("boot", result)
jedis.close()
}
}val server = RedisServer(
port = 6379, // Port number (default: 6379)
host = "0.0.0.0" // Bind address (default: 0.0.0.0)
)| Property | Type | Default | Description |
|---|---|---|---|
embedded.redis.enabled |
Boolean | true |
Enable/disable embedded Redis |
embedded.redis.port |
Integer | 6379 |
Port for Redis server |
embedded.redis.host |
String | localhost |
Host address to bind |
embedded.redis.auto-start |
Boolean | true |
Auto-start server on app startup |
Replace actual Redis with embedded version for fast, isolated tests.
Test Redis-dependent code without external Redis installation.
Develop applications without installing Redis.
Run tests in CI without Redis setup complexity.
Quick demos without infrastructure setup.
- In-Memory Only: All data stored in memory (not persisted to disk)
- Single-Threaded: While coroutines handle concurrency, operations are sequential
- Development/Testing: Optimized for development/testing, not production workloads
- Memory: Monitor memory usage for large datasets
| Feature | Embedded Redis Server | redis-mock | embedded-redis | testcontainers-redis |
|---|---|---|---|---|
| Protocol Compliant | ✅ RESP2 | ✅ Yes | ✅ Yes | |
| Spring Boot Auto-Config | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Pure JVM | ✅ Yes | ✅ Yes | ❌ No (native) | ❌ No (Docker) |
| Lightweight | ✅ Yes | ✅ Yes | ❌ Heavy | |
| No External Dependencies | ✅ Yes | ✅ Yes | ❌ Docker required |
- Not Production Ready: For development/testing only
- Limited Commands: Core commands implemented, advanced features not available
- No Persistence: Data not saved to disk
- No Clustering: Single instance only
- No Pub/Sub: Not yet implemented
- No Transactions: Not yet implemented
- Additional Redis commands (INCR, DECR, ... )
- Pub/Sub support
- Transaction support (MULTI/EXEC)
- Lua scripting
- AOF/RDB persistence (optional)
- RESP3 protocol support
- Java 21 or higher
- Kotlin 1.9.22 or higher
- Spring Boot 3.2+ (for Spring integration)
# Clone the repository
git clone https://github.com/sudouser777/embedded-redis-server.git
cd embedded-redis-server
# Build with Gradle
./gradlew build
# Run tests
./gradlew test
# Publish to local Maven repository
./gradlew publishToMavenLocalContributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Inspired by H2 Database embedded mode
- Built with Kotlin Coroutines for concurrency
- Uses RESP2 protocol specification
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- redis-mock - Mock implementation of Redis
- embedded-redis - Embedded Redis using native binaries
- testcontainers-redis - Docker-based Redis for tests
Made with ❤️ using Kotlin