TIL
Every net/http request runs in its own goroutine
In Go’s net/http, the server starts a new goroutine for each incoming request. So your handlers run concurrently by default, even if you never wrote a single go statement.
That means any state a handler touches across requests has to be safe for concurrent use. If you share a mutable value (a map, a counter, a cached struct) without a mutex, you have a data race waiting to happen.
The safe options: keep state per request (local variables, the request context), or guard shared state with a mutex. I had been treating handlers like they ran one at a time. They don’t.