| name | go-context |
| description | Use when working with context.Context in Go — placement in signatures, propagating cancellation and deadlines, and storing values in context vs parameters. Also use when cancelling long-running operations, setting timeouts, or passing request-scoped data, even if they don't mention context.Context directly. Does not cover goroutine lifecycle or sync primitives (see go-concurrency). |
Go Context Usage
Compatibility: context has been in the standard library since Go 1.7.
Resource Routing
references/PATTERNS.md - Read when deriving contexts, checking cancellation, handling HTTP request contexts, or using typed context-value keys.
Context as First Parameter
Functions that use a Context should accept it as their first parameter:
func F(ctx context.Context, /* other arguments */) error
func ProcessRequest(ctx context.Context, req *Request) (*Response, error)
This is a strong convention in Go that makes context flow visible and consistent
across codebases.
Don't Store Context in Structs
Do not add a Context member to a struct type. Instead, pass ctx as a parameter
to each method that needs it:
type Worker struct {
ctx context.Context
}
type Worker struct{ }
func (w *Worker) Process(ctx context.Context) error {
}
Exception: Methods whose signature must match an interface in the standard
library or a third-party library may need to work around this.
Don't Create Custom Context Types
Do not create custom Context types or use interfaces other than context.Context
in function signatures:
type MyContext interface {
context.Context
GetUserID() string
}
func Process(ctx context.Context) error {
userID := GetUserID(ctx)
}
Where to Put Application Data
Consider these options in order of preference:
- Function parameters — most explicit and type-safe
- Receiver — for data that belongs to the type
- Globals — for truly global configuration (use sparingly)
- Context value — only for request-scoped data
Context values are appropriate for:
- Request IDs and trace IDs
- Authentication/authorization info that flows with requests
- Deadlines and cancellation signals
Context values are not appropriate for:
- Optional function parameters
- Data that could be passed explicitly
- Configuration that doesn't vary per-request
Common Patterns
Deriving Contexts
Always defer cancel() immediately after creating a derived context:
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
Checking Cancellation
select {
case <-ctx.Done():
return ctx.Err()
default:
}
Context Immutability
Contexts are immutable — it's safe to pass the same ctx to multiple
concurrent calls that share the same deadline and cancellation signal.
Related Skills
- Goroutine coordination: See go-concurrency when using context for goroutine cancellation, select-based timeouts, or errgroup
- Error handling: See go-error-handling when deciding how to wrap or return
ctx.Err() cancellation errors
- Interface design: See go-interfaces when designing APIs that accept context alongside interfaces
- Request-scoped logging: See go-logging when injecting loggers into context or adding request IDs to structured log output