A tiny key-value store built from scratch in TypeScript — a small slice of Redis. Clients connect over TCP and send text commands. Data lives in memory but survives crashes thanks to a write-ahead log.
- In-memory store with a simple text protocol over TCP
SET/GET/DEL/GETALLcommands- Write-ahead log (WAL) with
fsync— writes are safe on disk before they touch memory - Crash recovery — the store rebuilds itself from the log on startup
- LRU eviction — caps the store at 5 keys and drops the least-recently-used one
- Node.js
ts-nodeand Node type definitions:
npm install --save-dev @types/node
npx ts-node server.ts
The server listens on 127.0.0.1:3400. You should see:
recovered N keys from log
server listening on port 3400
In a second terminal, connect with netcat:
nc localhost 3400
Then type commands:
SET name Apple -> OK
GET name -> Apple
GETALL -> name = Apple
DEL name -> 1
GET name -> (nil)
| Command | What it does | Reply |
|---|---|---|
SET <key> <val> |
Store or overwrite a key | OK |
GET <key> |
Read a key | value or (nil) |
DEL <key> |
Delete a key | 1 or 0 |
GETALL |
List every key and value | list or (empty) |
Write-ahead log. Before a write (SET/DEL) changes memory, it's appended to
store.log and flushed to disk with fsync. So even if the server crashes a moment
later, the change is already safe on disk. Reads (GET) change nothing, so they're
never logged.
Recovery. On startup, the server reads store.log and replays every command back
into memory — rebuilding the exact state it had before shutdown.
LRU eviction. The store holds at most 5 keys. Touching a key (read or write) moves it to the "newest" position; when a new key would push the store over the limit, the oldest (least-recently-used) key is evicted.
- The log file
store.logis the source of truth on startup. Delete it to reset the store:rm store.log. - This is a learning project, not production software. Missing pieces on purpose: log compaction (the log grows forever), concurrency safety, and a binary protocol.