
Why I Rewrote My Side Project in Go
My Node.js chat server hit 60% CPU at 200 concurrent users. Six weeks later the Go rewrite handles 5,000 users at 8% CPU. Here's what I learned.
Backend Engineering with Go
Part 2 of 2 β’ Series Complete
A 2-part series covering real-world Go backend patterns β from WebSocket servers to rewriting production services.
Table of Contents
Table of Contents (4 sections)
The Problem
GoChat started as a Node.js/Socket.io application. At 200 concurrent WebSocket connections, the server was pegging at 60% CPU. By 500 connections, response latency exceeded 2 seconds and the event loop was visibly choking. The broadcast loop β iterating over 500 active socket connections β was CPU-bound work in a single-threaded environment.
To Be Fair to Node.js
Node.js is excellent for I/O-bound workloads β APIs, file serving, proxies. The problem was that broadcasting to 500 WebSocket connections is CPU-bound work that a single event loop cannot parallelize. This was a tool-fit problem, not a Node.js flaw.
Why Go, Specifically?
- Goroutines start at 2KB stack vs 1MB thread β comfortably 100k concurrent goroutines on a single VPS
- Built-in race detector: go test -race catches data races before production
- net/http is production-ready with no framework tax β no Express, no Fastify
- Single static binary with zero runtime dependencies β Docker images are 15MB
- Explicit error handling forces thinking about failure modes at every call site
ββConcurrency is not parallelism. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.β
β Rob Pike
The Migration
The rewrite took 6 weeks part-time. I kept the same WebSocket protocol so existing browser clients needed zero changes β only the server changed. The most time-consuming part was not the code; it was the mental model shift from callbacks to goroutines, and from shared mutable state to channel-based communication.
The Results
Six weeks later, the Go server was running in production on the same $6/month Hetzner VPS, the same Redis instance, and the same PostgreSQL database.
Benchmark Results β Same VPS, 5,000 Concurrent Users
Node.js: 60% CPU @ 200 users β OOM crash @ 1,000 users. Go: 8% CPU @ 5,000 users, 12ms p99 latency, stable 48MB memory. The Go rewrite handles 25Γ more concurrent users on identical hardware.
Would I recommend rewriting everything in Go? No β measure your bottleneck first. But for any system with long-lived connections and high concurrency requirements, Go should be your first choice. The go-ws-hub library packages the Hub pattern from this rewrite into a reusable, tested library.
Related Articles
Continue your learning journey with these handpicked articles.


Related Content
Explore related articles, projects, and tools.