Pitfalls of context values and how to avoid or mitigate them in Go

Storing data in a context.Context, or as I refer to it - using context values, is one of the most contentious design patterns in Go. Storing values in a context appears to be fine with everyone, but what specifically should be stored as a context value receives a lot of heated discussion.

I’ll be honest - when I started using them I used them in the naive and somewhat inappropriate way that everyone complains about. I used them to store just about every request-specific piece of data that my web application’s handlers might need to access. There were some downsides to this, but overall it tended to work well enough and allowed me to write my applications quickly.

Over the past month I have tried to dive into learning about a more proper use of context values, and in doing that I have come across many articles, Reddit comments, mailing list responses, and everything in between that discuss the matter, but one thing continued to bug me. No matter how much I dug, it felt like nobody was willing to discuss truly viable alternatives.

Sure, everyone could come up with reasons why using context values was bad, but none of the alternatives were fully fleshed out. Instead they were handy-wavy; things like “use custom structs” or “use closures” without any discussion about how that might actually get implemented in a more complicated application, or how that might affect reusability of middleware.

Today I am going to give my take on the matter. In this post we will discuss why using context values can become problematic, some alternative approaches that don’t use context values and when they are appropriate, and then finally we will discuss ways that you can use context values while avoiding or mitigating some of their potential downsides. But first, I want to start by discussing why developers use