Golang / GoLang Production Patterns and Web Standards Interview Questions
What are the best practices and anti-patterns for using context.WithValue?
context.WithValue should be used sparingly — only for request-scoped data that crosses API boundaries and would be impractical to pass as explicit parameters. It is not a general-purpose parameter-passing mechanism.
// ANTI-PATTERN: using a plain string as a context key ctx = context.WithValue(ctx, "userID", 42) // Any package can read/overwrite this key â key collisions guaranteed // CORRECT: define an unexported typed key per package // This prevents any other package from accidentally colliding type contextKey string const ( requestIDKey contextKey = "requestID" userIDKey contextKey = "userID" ) // Better: use a struct type as the key (common in stdlib) type requestIDKeyType struct{} func WithRequestID(ctx context.Context, id string) context.Context { return context.WithValue(ctx, requestIDKeyType{}, id) } func RequestIDFromContext(ctx context.Context) (string, bool) { id, ok := ctx.Value(requestIDKeyType{}).(string) return id, ok } // GOOD USES of context values: // - Request/trace IDs for logging and distributed tracing // - Authentication tokens / user identity // - Feature flags tied to the request // BAD USES of context values: // - Optional function parameters // - Database connections (pass as explicit dependency) // - Configuration that should be in a struct // - Anything that the function should document as a dependency // The Go proverb: 'Use context values only for request-scoped data // that transits processes and API boundaries, not for passing // optional parameters to functions.'
Context value lookups are O(n) in the number of values stored — each WithValue wraps the context in a new layer. Storing many values is inefficient. If you have many related values, wrap them in a single struct: context.WithValue(ctx, reqKey{}, &RequestData{UserID: 1, TraceID: "abc"}).
More Related questions...