A lightweight Redis-compatible server implementation written in TypeScript. This project implements core Redis functionality including string operations, list operations, streams, and transactions using the RESP (REdis Serialization Protocol).
- Strings: Basic key-value storage with operations like SET, GET, INCR
- Lists: Ordered collections with push/pop operations from both ends
- Streams: Append-only log data structure for event streaming
- Pub/Sub: Message broadcasting system for publish/subscribe pattern
PING- Test server connectivityECHO- Echo back a messageTYPE- Determine the type of a key
SET key value [EX seconds] [PX milliseconds]- Set a key-value pair with optional expirationGET key- Get value of a keyINCR key- Increment the integer value of a key
LPUSH key element [element ...]- Prepend elements to a listRPUSH key element [element ...]- Append elements to a listLPOP key- Remove and return the first elementLRANGE key start stop- Get a range of elements from a listLLEN key- Get the length of a listBLPOP key [key ...] timeout- Blocking left pop operation
XADD key ID field value [field value ...]- Append entry to a streamXRANGE key start end [COUNT count]- Query range of entries in a streamXREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]- Read data from streams
MULTI- Mark the start of a transaction blockEXEC- Execute all commands in a transactionDISCARD- Discard all commands in a transactionWATCH key [key ...]- Watch keys for conditional transaction execution
SUBSCRIBE channel [channel ...]- Subscribe to one or more channelsUNSUBSCRIBE [channel [channel ...]]- Unsubscribe from channelsPUBLISH channel message- Publish a message to a channel
-
Protocol Layer (
src/protocol/)- RESP parser and encoder for Redis protocol compliance
-
Storage Layer (
src/store/)- In-memory data store with support for multiple data types
- Client blocking management for blocking operations
-
Command Layer (
src/commands/)- Command registry and handler system
- Modular command implementations organized by data type
- Transaction management system
npm installBuild and run the server, then connect using redis-cli:
# Build the project
npm install
npm run build
# Start the server (listens on port 8001)
npm start
# In a new terminal, connect with redis-cli
redis-cli -p 8001Don't have redis-cli installed? Use Docker:
docker run --rm -it --add-host=host.docker.internal:host-gateway redis:7 redis-cli -h host.docker.internal -p 8001Run the server with hot-reloading:
npm run devExample session:
127.0.0.1:8001> PING
PONG
127.0.0.1:8001> SET mykey "Hello"
OK
127.0.0.1:8001> GET mykey
"Hello"
127.0.0.1:8001> RPUSH mylist "item1" "item2"
(integer) 2
127.0.0.1:8001> LRANGE mylist 0 -1
1) "item1"
2) "item2"src/
├── commands/
│ ├── commandHandler.ts # Main command dispatcher
│ ├── commandRegistry.ts # Command registration
│ ├── ping.ts # PING command
│ ├── lists/ # List operations
│ ├── stream/ # Stream operations
│ ├── strings/ # String operations
│ └── transactions/ # Transaction support
├── protocol/
│ ├── encodeRESP.ts # RESP encoder
│ └── parseRESP.ts # RESP parser
├── store/
│ └── memoryStore.ts # In-memory storage
└── utils/
├── isEqual.ts # Utility functions
└── types.ts # Type definitions
npm run type-checknpm run build:watchThe server implements the Redis Serialization Protocol (RESP), supporting:
- Simple Strings
- Errors
- Integers
- Bulk Strings
- Arrays
- Null values
Implements optimistic locking with WATCH/MULTI/EXEC:
- Commands are queued during MULTI
- WATCH monitors keys for changes
- EXEC atomically executes queued commands if watched keys haven't changed
- DISCARD cancels the transaction
The server supports blocking operations like BLPOP:
- Clients are blocked until data is available or timeout occurs
- Automatic cleanup on client disconnect
- Notification system for waking blocked clients
- Node.js (v18 or higher recommended)
- TypeScript 5.9+