This repository is a small, educational implementation of a Redis-like server in Go.
It's based on the "Build Your Own Redis" challenge and implements a subset of the
Redis command set with the RESP protocol so you can connect using the official
redis-cli for basic interactions.
This file documents the project, its structure, which Redis commands are
implemented, how to run the server locally, and example usage with redis-cli.
- Language: Go
- Entry point:
app/main.go(server listens on0.0.0.0:6379by default) - Local run helper:
./your_program.sh(builds and runs the binary) - RESP compatibility: implemented for the commands listed below —
redis-clican connect to this server for those commands.
app/— application sourcesmain.go— program entrypoint, accepts TCP connections on port 6379resp/— RESP parsing and command dispatchresp.go— RESP reader, parser andCommandsMapcommands/— implemented command handlersbasic.go—PING,ECHO,COMMAND,TYPEhash_map.go—SET,GET(string key/value with optional TTL)list.go— list commands:RPUSH,LPUSH,LRANGE,LLEN,LPOP,BLPOPstream.go—XADD(basic stream add behavior)
connection/— connection manager utilitiescontext/— connection context passed to command handlersmemory/— in-memory data structures (hash map, lists, streams)resp/commands/— implementations referenced above
your_program.sh— helper script to build and run the server locallyREADME.md— original challenge READMEREADME2.md— this file (detailed project README)
The server registers the following commands in resp.CommandsMap and provides
basic behavior for them:
-
PING
- Usage:
PING - Response:
PONG(+PONG\r\nin RESP)
- Usage:
-
ECHO
- Usage:
ECHO <message> - Response: bulk string containing the message
- Usage:
-
COMMAND
- Usage:
COMMAND - Response: empty array (
*0) — placeholder (not full COMMAND support)
- Usage:
-
SET
- Usage:
SET <key> <value> [EX <seconds>|PX <milliseconds>] - Supported options:
EXandPXfor expirations. - Response:
+OKon success
- Usage:
-
GET
- Usage:
GET <key> - Behavior: returns the stored value or
$-1if not found. If a TTL was set atSETtime and the key has expired it will be removed and treated as missing.
- Usage:
-
TYPE
- Usage:
TYPE <key> - Response:
string,list,streamornonedepending on what holds the key
- Usage:
-
RPUSH
- Usage:
RPUSH <key> <element> [element ...] - Response: integer (the new length of the list)
- Usage:
-
LPUSH
- Usage:
LPUSH <key> <element> [element ...] - Response: integer (the new length of the list)
- Usage:
-
LRANGE
- Usage:
LRANGE <key> <start> <stop> - Response: array of elements in the given range
- Usage:
-
LLEN
- Usage:
LLEN <key> - Response: integer (length of the list)
- Usage:
-
LPOP
- Usage:
LPOP <key>orLPOP <key> <count> - Response: single bulk string when popping one element, or array when popping
count. - If the key does not exist, returns a nil bulk (
$-1) or*-1in some multi-return cases
- Usage:
-
BLPOP
- Usage:
BLPOP <key> <key> ... <timeout> - Behavior: basic blocking pop implementation. The server blocks for the
timeout duration and returns
*-1on timeout.
- Usage:
-
XADD
- Usage:
XADD <stream> <id> <field> <value> [<field> <value> ...] - Implementation: basic append behavior — stores pairs (field/value) under a stream key and returns the provided id or added item identifier in a simplified form.
- Usage:
Note: This is a toy subset. The server implements the RESP format for these
commands well enough to interoperate with redis-cli for the examples shown
below, but does not offer full command parity with upstream Redis.
Requirements:
- Go toolchain (the project currently uses Go modules). Go 1.24 or later is
recommended (match your local setup with
go version).
Build + run (recommended — uses the provided helper script):
./your_program.shThis will build the program and run the server on port 6379. You can also
build and run directly with the Go toolchain:
go build -o /tmp/codecrafters-build-redis-go app/*.go
/tmp/codecrafters-build-redis-goWhen running, the server listens on 0.0.0.0:6379 (see app/main.go).
Because the server speaks the RESP protocol, you can use the official redis-cli
to connect to it. From another terminal run:
# Connect to localhost on default Redis port
redis-cli -p 6379
# Or specify host and port explicitly
redis-cli -h 127.0.0.1 -p 6379Inside the redis-cli prompt you can issue the implemented commands. Examples:
$ redis-cli -p 6379
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> SET mykey hello
OK
127.0.0.1:6379> GET mykey
"hello"
127.0.0.1:6379> RPUSH mylist a b c
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> TYPE mykey
"string"
If you prefer to test single commands without an interactive prompt, you can
also pipe or pass commands directly to redis-cli:
redis-cli -p 6379 PING
redis-cli -p 6379 SET foo bar
redis-cli -p 6379 GET fooredis-cli -p 6379 SET tempkey 123 EX 1
OK
# Wait >1 second
redis-cli -p 6379 GET tempkey
(nil)- Not all Redis commands or options are implemented.
COMMANDreturns an empty array and some advanced behaviors are simplified. - Persistence is not included — the data lives only in memory while the server process is running.
- Concurrency and performance are suitable for learning and tests but not for production use.
- The RESP parser in
app/resp/resp.goreads from the connection in a single large buffer — large requests or streaming corner cases may need additional handling in a complete implementation.
If you want to add commands:
- Implement the handler function in
app/resp/commands/(follow existing examples). - Register the command name and handler in
app/resp/resp.goCommandsMap. - Add unit tests (not included here) and run the server to verify.
This project is meant for learning and the challenge environment. The server is
RESP-compatible for the implemented commands and works with the official
redis-cli for interactive testing.