askill
go-context

go-contextSafety 95Repository

Context propagation, cancellation, timeouts, and value storage patterns. Use when managing request lifecycles, implementing timeouts, storing context values with type-safe context keys, or coordinating goroutine cancellation across service boundaries.

0 stars
1.2k downloads
Updated 2/11/2026

Package Files

Loading files...
SKILL.md

Go Context

Context is the first parameter, flows through call chains, never lives in structs.

Decision Framework: Context Creation

Create ContextUse CaseExample
context.Background()Top-level (main, tests, initialization)Program startup, test setup
context.TODO()Placeholder when context unclearRefactoring legacy code
WithTimeout(parent, duration)Operations with time limitsHTTP calls, database queries
WithCancel(parent)Manual cancellation neededWorker pools, streaming
WithDeadline(parent, time)Absolute deadlineBatch jobs, scheduled tasks
WithValue(parent, key, val)Request-scoped dataTrace IDs, user context
WithoutCancel(parent)Detach from parent cancellation (Go 1.21+)Background work after response sent

Decision Rule: Start with Background/TODO at boundaries, derive child contexts with timeouts/cancellation as needed.

Pattern 1: HTTP Handler with Timeout

Every HTTP handler receives a context. Derive child contexts for downstream calls.

func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context() // Always use request context

	// Add timeout for database query
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	user, err := h.repo.FindByID(ctx, userID)
	if err != nil {
		if errors.Is(err, context.DeadlineExceeded) {
			http.Error(w, "request timeout", http.StatusGatewayTimeout)
			return
		}
		http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}

	json.NewEncoder(w).Encode(user)
}

Pattern 2: Type-Safe Context Values

Use custom types for context keys to avoid collisions.

type contextKey string

const (
	traceIDKey  contextKey = "trace_id"
	userIDKey   contextKey = "user_id"
)

// Store value in context
func WithTraceID(ctx context.Context, traceID string) context.Context {
	return context.WithValue(ctx, traceIDKey, traceID)
}

// Retrieve value from context
func GetTraceID(ctx context.Context) (string, bool) {
	traceID, ok := ctx.Value(traceIDKey).(string)
	return traceID, ok
}

// Usage in middleware
func TracingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		traceID := r.Header.Get("X-Trace-ID")
		if traceID == "" {
			traceID = uuid.New().String()
		}

		ctx := WithTraceID(r.Context(), traceID)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

Rules:

  • Use custom type for keys (not string or int)
  • Create accessor functions (WithX, GetX) for type safety
  • Context values should be request-scoped, immutable data
  • Avoid using context for optional parameters

Goroutine Cancellation

For patterns on using context to coordinate goroutine lifecycle (errgroup, worker pools, fan-out), see the go-concurrency skill.

Decision Framework: When to Use Context Values

Use Context ValuesUse Explicit Parameters
Request-scoped data (trace IDs, correlation IDs)Business logic parameters
Authentication credentials (user ID, tokens)Function behavior configuration
Cross-cutting concerns (logging, tracing)Domain data and entities
Data that flows through middlewareOptional parameters

Decision Rule: Ask "Is this data about the request itself, or is it a business parameter?" Request metadata → context. Business data → parameters.

Pattern 3: Detaching from Cancellation (Go 1.21+)

Use context.WithoutCancel when work must continue after the parent context is cancelled, while preserving the parent's values.

func (h *Handler) SubmitOrder(w http.ResponseWriter, r *http.Request) {
	order, err := h.orders.Create(r.Context(), req)
	if err != nil {
		http.Error(w, "failed", http.StatusInternalServerError)
		return
	}

	// Send confirmation email after responding — must not be cancelled
	// when the HTTP request ends. Values (trace ID, user ID) are preserved.
	go h.mailer.SendConfirmation(context.WithoutCancel(r.Context()), order)

	json.NewEncoder(w).Encode(order)
}

When to use: Post-response async work (emails, audit logs, cache warming) that needs the parent's values but must outlive the parent's cancellation. Prefer this over context.Background() to retain request-scoped values like trace IDs.

Anti-Patterns

Storing context in struct

// BAD: Context stored in struct
type Service struct {
	ctx context.Context
	db  *sql.DB
}

func (s *Service) DoWork() error {
	return s.db.QueryRowContext(s.ctx, "SELECT ...") // Stale context!
}

// GOOD: Context passed as parameter
type Service struct {
	db *sql.DB
}

func (s *Service) DoWork(ctx context.Context) error {
	return s.db.QueryRowContext(ctx, "SELECT ...")
}
  • String keys for context values — Use custom types (see Pattern 2), never bare strings or ints
  • Ignoring context cancellation — Always check ctx.Done() in loops; use select with ticker instead of time.Sleep
  • Creating Background context in inner functions — Never create context.Background() inside a call chain; pass the parent context through
  • Unrealistic timeouts — Set timeouts based on expected operation duration, not arbitrary values

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

94/100Analyzed 2/19/2026

High-quality technical reference skill covering Go context patterns comprehensively. Includes decision frameworks, multiple code patterns (HTTP timeout, type-safe values, detaching cancellation), anti-patterns, and clear usage guidance. Well-organized with tables and examples. Located in proper skills folder with relevant tags. No internal-only indicators.

95
95
95
90
95

Metadata

Licenseunknown
Version-
Updated2/11/2026
Publisherdeandum

Tags

apidatabaseobservabilitytesting