context.TODO

April 3, 2025

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 to context.Background(). In fact, the only difference between the two, is their implementation of the String() 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 simple grep.

    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 use context.Background() instead. In non-test code, if you’re unusre, use context.TODO().


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe