Overview
…
Do not pass a nil Context, even if a function permits it. Pass context.TODO if you are unsure about which Context to use.
Two pieces of advice in today’s section. I’m going to tackle them in reverse, though.
-
Use
context.TODO()
if you are unsure which Context to use.Functionally
context.TODO()
is identical tocontext.Background()
. In fact, the only difference between the two, is their implementation of theString()
method, as we can see by reading the source:type backgroundCtx struct{ emptyCtx } func (backgroundCtx) String() string { return "context.Background" } type todoCtx struct{ emptyCtx } func (todoCtx) String() string { return "context.TODO" }
So why not just use
context.Background()
?Documentation and searchability.
First,
context.TODO()
documents that you were unsure of which context to use, and the decision should be revisited at a later time when more information is available.Second,
context.TODO()
is easily found with static analysis tools, or even a simplegrep
.I often use
context.TODO()
when updating an old code base to use contexts. I may find myself needing a context where one hasn’t been received.context.TODO()
is the perfect marker that satisfies the immediate need, and simultaneously makes it clear that further context plumbing is needed when feasible. -
Do not pass a nil
Context
This is a mistake I often see newcomers make—especially when writing tests. “The function works fine with
nil
, and I don’t have one, so what’s the harm?”Fair question. What is the harm?
First, it’s just part of the (unenforced) API contract that
nil
contexts should never be used. This simplifies your life as the author of code that accepts a context–you don’t need to check for nil values.Second, if a function works fine with a nil context, that’s likely a code smell. It’s an indication, though certainly not a guarantee, the function may be incomplete.
Third, code changes all the time. A function that works today with a
nil
context may break tomorrow, when new capabilities are added. If code in other places (maybe even other repos, if you’re building a library) suddenly starts breaking, that’s not good.And finally, there’s never any advantage to using a
nil
context. In a test, just usecontext.Background()
instead. In non-test code, if you’re unusre, usecontext.TODO()
.