HTTP/1.1 server built from raw TCP sockets using only node:net. No Express, no http module - just bytes on a wire.
To understand what actually happens between socket.on('data') and your route handler receiving a parsed request object. Most Node.js developers use Express without knowing what it abstracts away. This project removes those abstractions.
| Concept | What You Discover |
|---|---|
| TCP framing | HTTP has no "message boundary" - you detect \r\n\r\n and Content-Length yourself |
| Event loop | socket.on('data') fires per TCP chunk, not per HTTP request |
| Backpressure | socket.write() returns false when the kernel buffer is full |
| Keep-Alive | One TCP connection serves multiple requests serially via a state machine |
| Buffer | Raw bytes, not strings. Buffer.indexOf() to find header boundaries |
- Step 1: TCP echo server - accept connections, echo data back
- Step 2: HTTP request parser - state machine for parsing raw bytes into requests
- Step 3: Response builder - construct valid HTTP/1.1 responses
- Step 4: Router - path matching, param extraction, handler dispatch
- Step 5: Keep-Alive - multiple requests per connection
- Step 6: Static file serving - streaming with backpressure
- Step 7: Benchmarks - throughput comparison vs Express
This is a guided learning project. Code is split between:
- AI (Claude): Project scaffolding, type definitions, config, test cases, boilerplate, glue code
- Human: Core algorithms, state machines, parsers, design decisions - the parts that require understanding
Each commit message documents exactly which files/lines were written by whom.
# Echo server (Step 1)
bun run src/echo-server.ts
# Test with netcat
echo "hello" | nc localhost 3004
# Run tests
bun test- TypeScript (strict mode)
- Bun runtime
- Vitest for testing
node:netfor raw TCP (the whole point)