The Singleflight Pattern: Collapsing Concurrent Identical Requests Into One

2026-07-01

You have a service that fetches user profiles from a slow upstream API. A hot user's profile expires from cache. In the next 50ms, 200 requests all miss the cache and stampede the upstream. You just turned one cache miss into 200 duplicate fetches — burning latency, quota, and money on identical work.

Singleflight (popularized by Go's golang.org/x/sync/singleflight) solves this: when N goroutines ask for the same key at the same time, exactly one does the work, and the other N-1 wait for its result. It's dogpile prevention scoped to a single process — no Redis, no distributed locks, no coordination overhead.

How it works: a map keyed by the request identifier holds an in-flight call object (a promise, essentially). First caller inserts the entry and starts the fetch. Subsequent callers find the existing entry and block on its completion channel. When the fetch returns, everyone gets the same result — success or error — and the entry is deleted.

Concrete example: a GraphQL resolver that loads product details by SKU. Under load, the same SKU appears in dozens of concurrent queries. Wrap the loader:

The math: if your fetch takes 100ms and you get 500 requests/second for a hot key, without singleflight you do ~50 concurrent fetches at any moment. With singleflight, you do one. Load reduction ≈ concurrent requests per key during the fetch window. Higher fanout, bigger win.

The gotchas:

Singleflight is one of those 30-line patterns that pays for itself the first time a hot key expires under load. Reach for it whenever your read path has expensive, idempotent, keyable work behind it.

See it in action: Check out Caching Pitfalls Every Developer Should Know by ByteByteGo to see this theory applied.
Key Takeaway: When many concurrent callers ask for the same thing, do the work once and share the answer — but remember failure is shared too.

All newsletters