Context deadlines

May 19, 2025

On Friday we looked at the context.Context interface as a whole. Now let’s go back and look at each method in greater detail.

type Context

type Context interface {
 	// Deadline returns the time when work done on behalf of this context
	// should be canceled. Deadline returns ok==false when no deadline is
	// set. Successive calls to Deadline return the same results.
	Deadline() (deadline time.Time, ok bool)

So there are two general cases here:

deadline, ok := ctx.Deadline()
if ok {
	// The context has a deadline
	fmt.Println("This context will timeout at %v", deadline)
} else {
	// The context has no deadline, `deadline`'s value is meaningless
	fmt.Println("This context has no deadline")
}

You can see it in action.

Seems pretty simple, right? It is.

However, there are a couple of subtleties at play that are worth calling out:

  1. As already discussed, a call to context.WithTimeout actually sets a deadline. So calling ctx.Deadline() on a context with a timeout (as done in the above playground link) will return a concrete time.

  2. Also as previously mentioned in the documentation for the relevant functions, in cases where more than one context in a context chain include a deadline (or timeout), only the earliest is effective. So calling ctx.Deadline() may return a deadline earlier than some deadline or timeout you set, if the parent context already has an earlier deadline:

parent, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()

/* ... somewhere later ... */

ctx, cancel := context.WithTimeout(parent, 30 * time.Second)
defer cancel()

deadline, _ := ctx.Deadline() // Here `deadline`, will reflect a 5-second timeout, not 30.

Share this

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

Unsure? Browse the archive .

Related Content


Context cancelation

As already mentioned, the context.Context type serves two purposes: It manages cancelation signals, and it allows passing request-scoped data. In my opinion, these two purposes are distinct enough that they probably should be handled by two separate mechanisms. But alas, that’s not what we have. However, I think it’s still useful to think of the two uses as distinct. Most often (at least in a well-designed application), the primary purpose of a context is the propegation of cancelation signals.


Contexts with timeouts

func WithTimeout func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete: func slowOperationWithTimeout(ctx context.Context) (Result, error) { ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() // releases resources if slowOperation completes before timeout elapses return slowOperation(ctx) } Not only is WithTimeout conceptually similar to WithDeadline, it literally is WithDeadline, as we can see form the source code:


context.WithoutCancel

This is it! The last of the context package functions that we will cover in this series. Well, almost. I actually have a couple reader feedback and question emails to respond to, which I’ll do next, before startinga a new series. Speak of a new series: I’m still looking for suggestions! I have a couple ideas, but I’d rather do something you’re itching to learn about, than whatever random idea I come up with.

Get daily content like this in your inbox!

Subscribe