Community default. A company skill that explicitly supersedes samber/cc-skills-golang@golang-context skill takes precedence.
Go context.Context Best Practices
context.Context is Go's mechanism for propagating cancellation signals, deadlines, and request-scoped values across API boundaries and between goroutines. Think of it as the "session" of a request — it ties together every operation that belongs to the same unit of work.
Best Practices Summary
- The same context MUST be propagated through the entire request lifecycle: HTTP handler → service → DB → external APIs
ctx MUST be the first parameter, named ctx context.Context
- NEVER store context in a struct — pass explicitly through function parameters
- NEVER pass
nil context — use context.TODO() if unsure
cancel() MUST be called on all control-flow paths for WithCancel/WithTimeout/WithDeadline, unless ownership of the context and cancel function is explicitly returned or transferred
context.Background() MUST only be used at the top level (main, init, tests)
- Use
context.TODO() as a placeholder when you know a context is needed but don't have one yet
- NEVER create a new
context.Background() in the middle of a request path
- Context value keys MUST be unexported types to prevent collisions
- Context values MUST only carry request-scoped metadata — NEVER function parameters
- Use
context.WithoutCancel (Go 1.21+) when spawning background work that must outlive the parent request
Creating Contexts
| Situation |
Use |
| Entry point (main, init, test) |
context.Background() |
| Function needs context but caller doesn't provide one yet |
context.TODO() |
| Inside an HTTP handler |
r.Context() |
| Need cancellation control |
context.WithCancel(parentCtx) |
| Need a deadline/timeout |
context.WithTimeout(parentCtx, duration) |
Context Propagation: The Core Principle
The most important rule: propagate the same context through the entire call chain. When you propagate correctly, cancelling the parent context cancels all downstream work automatically.
// ✗ Bad — creates a new context, breaking the chain
func (s *OrderService) Create(ctx context.Context, order Order) error {
return s.db.ExecContext(context.Background(), "INSERT INTO orders ...", order.ID)
}
// ✓ Good — propagates the caller's context
func (s *OrderService) Create(ctx context.Context, order Order) error {
return s.db.ExecContext(ctx, "INSERT INTO orders ...", order.ID)
}
Deep Dives
Cancellation, Timeouts & Deadlines — How cancellation propagates: WithCancel for manual cancellation, WithTimeout for automatic cancellation after a duration, WithDeadline for absolute time deadlines. Patterns for listening (<-ctx.Done()) in concurrent code, AfterFunc callbacks, and WithoutCancel for operations that must outlive their parent request (e.g., audit logs).
Context Values & Cross-Service Tracing — Safe context value patterns: unexported key types to prevent namespace collisions, when to use context values (request ID, user ID) vs function parameters. Trace context propagation: OpenTelemetry trace headers, correlation IDs for log aggregation, and marshaling/unmarshaling context across service boundaries.
Context in HTTP Servers & Service Calls — HTTP handler context: r.Context() for request-scoped cancellation, middleware integration, and propagating to services. HTTP client patterns: NewRequestWithContext, client timeouts, and retries with context awareness. Database operations: always use *Context variants (QueryContext, ExecContext) to respect deadlines.
Cross-References
- → See the
samber/cc-skills-golang@golang-concurrency skill for goroutine cancellation patterns using context
- → See the
samber/cc-skills-golang@golang-database skill for context-aware database operations (QueryContext, ExecContext)
- → See the
samber/cc-skills-golang@golang-observability skill for trace context propagation with OpenTelemetry
- → See the
samber/cc-skills-golang@golang-design-patterns skill for timeout and resilience patterns
Enforce with Linters
Many context pitfalls are caught automatically by linters: govet, staticcheck. → See the samber/cc-skills-golang@golang-lint skill for configuration and usage.
1---2name: golang-context3description: Idiomatic context.Context usage in Golang — propagation through API boundaries, cancellation, timeouts and deadlines, request-scoped values, context.WithoutCancel for background work outliving requests. Apply when designing context propagation across layers, debugging leaked or unexpired contexts, choosing between context.Background/TODO/WithoutCancel, or storing values in context. Not for code that merely accepts ctx as first parameter.4license: MIT5---67> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-context` skill takes precedence.89# Go context.Context Best Practices1011`context.Context` is Go's mechanism for propagating cancellation signals, deadlines, and request-scoped values across API boundaries and between goroutines. Think of it as the "session" of a request — it ties together every operation that belongs to the same unit of work.1213## Best Practices Summary14151. The same context MUST be propagated through the entire request lifecycle: HTTP handler → service → DB → external APIs162. `ctx` MUST be the first parameter, named `ctx context.Context`173. NEVER store context in a struct — pass explicitly through function parameters184. NEVER pass `nil` context — use `context.TODO()` if unsure195. `cancel()` MUST be called on all control-flow paths for `WithCancel`/`WithTimeout`/`WithDeadline`, unless ownership of the context and cancel function is explicitly returned or transferred206. `context.Background()` MUST only be used at the top level (main, init, tests)217. **Use `context.TODO()`** as a placeholder when you know a context is needed but don't have one yet228. NEVER create a new `context.Background()` in the middle of a request path239. Context value keys MUST be unexported types to prevent collisions2410. Context values MUST only carry request-scoped metadata — NEVER function parameters2511. **Use `context.WithoutCancel`** (Go 1.21+) when spawning background work that must outlive the parent request2627## Creating Contexts2829| Situation | Use |30| --- | --- |31| Entry point (main, init, test) | `context.Background()` |32| Function needs context but caller doesn't provide one yet | `context.TODO()` |33| Inside an HTTP handler | `r.Context()` |34| Need cancellation control | `context.WithCancel(parentCtx)` |35| Need a deadline/timeout | `context.WithTimeout(parentCtx, duration)` |3637## Context Propagation: The Core Principle3839The most important rule: **propagate the same context through the entire call chain**. When you propagate correctly, cancelling the parent context cancels all downstream work automatically.4041```go42// ✗ Bad — creates a new context, breaking the chain43func (s *OrderService) Create(ctx context.Context, order Order) error {44 return s.db.ExecContext(context.Background(), "INSERT INTO orders ...", order.ID)45}4647// ✓ Good — propagates the caller's context48func (s *OrderService) Create(ctx context.Context, order Order) error {49 return s.db.ExecContext(ctx, "INSERT INTO orders ...", order.ID)50}51```5253## Deep Dives5455- **[Cancellation, Timeouts & Deadlines](./references/cancellation.md)** — How cancellation propagates: `WithCancel` for manual cancellation, `WithTimeout` for automatic cancellation after a duration, `WithDeadline` for absolute time deadlines. Patterns for listening (`<-ctx.Done()`) in concurrent code, `AfterFunc` callbacks, and `WithoutCancel` for operations that must outlive their parent request (e.g., audit logs).5657- **[Context Values & Cross-Service Tracing](./references/values-tracing.md)** — Safe context value patterns: unexported key types to prevent namespace collisions, when to use context values (request ID, user ID) vs function parameters. Trace context propagation: OpenTelemetry trace headers, correlation IDs for log aggregation, and marshaling/unmarshaling context across service boundaries.5859- **[Context in HTTP Servers & Service Calls](./references/http-services.md)** — HTTP handler context: `r.Context()` for request-scoped cancellation, middleware integration, and propagating to services. HTTP client patterns: `NewRequestWithContext`, client timeouts, and retries with context awareness. Database operations: always use `*Context` variants (`QueryContext`, `ExecContext`) to respect deadlines.6061## Cross-References6263- → See the `samber/cc-skills-golang@golang-concurrency` skill for goroutine cancellation patterns using context64- → See the `samber/cc-skills-golang@golang-database` skill for context-aware database operations (QueryContext, ExecContext)65- → See the `samber/cc-skills-golang@golang-observability` skill for trace context propagation with OpenTelemetry66- → See the `samber/cc-skills-golang@golang-design-patterns` skill for timeout and resilience patterns6768## Enforce with Linters6970Many context pitfalls are caught automatically by linters: `govet`, `staticcheck`. → See the `samber/cc-skills-golang@golang-lint` skill for configuration and usage.