If you're coming from a language like PHP, Go's concept of context might feel completely alien. Here I explain mental model I use while working with it.

What context is not

Not a dependency container

The dependencies should usually be initiated at the application startup and passed to the services that are also initiated at startup. You set up the scene before you perform the actions. Context is not global, it's a request-scoped artifact by purpose. It's not supposed to hold global dependencies, only the data specific to a request.

Not a variable container

If you have a function with many expected arguments then simplifying the interface by putting the arguments to the context is not the right way to go (pun intended). That would not really simplify the function. In fact it would only obscure it because now the variables are still required but the requirement is implicit, not explicitly stated in function's signature.

How to think about context

As I said earlier the context is about a single request. This request has its own data that the subsequent functions might need to know and it has a lifecycle that needs to be controlled.

For holding request-specific data

A single request has data that is specific to it like trace ID or authorized user's ID. The subsequent function calls might query the context for those. For example a logging function might fetch the trace ID. The function executing the restricted functionalities might query the context for user's ID. A request can have many of them and defining them as arguments in function's signature would clutter it, resulting in limited testability.

For controlling the request lifecycle

The request might be aborted mid flight, whether it's a http request or some other. It might hit timeout or be aborted by the user. Signaling with the .Done() channel on context lets us handle this gracefully. You decide how to close connections, clean up the filesystem or roll back the changes instead of them being forcefully closed for you.

The context is not complicated, but it might be confusing for developers coming from other languages where it was not present (PHP) or was niche (Python). It helps when you think about it as a "control center" for the request instead of just some cryptic creation that some libs force you to use or a shortcut to simplify your interfaces.