How to Pass Context in Go: Simple Guide with Examples
In Go, you pass
context.Context as the first argument to functions that need cancellation, deadlines, or request-scoped values. Use context.Background() or context.TODO() to create a root context, then pass it down through function calls.Syntax
In Go, functions that accept context take a context.Context as their first parameter. You create a root context with context.Background() or context.TODO(). You can derive new contexts with cancellation or deadlines using context.WithCancel, context.WithTimeout, or context.WithDeadline.
Example syntax:
func doWork(ctx context.Context) {
// use ctx inside
}go
func doWork(ctx context.Context) {
// use ctx inside
}Example
This example shows how to create a context with cancellation and pass it to a function that listens for cancellation to stop work early.
go
package main import ( "context" "fmt" "time" ) func doWork(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("Work cancelled:", ctx.Err()) return default: fmt.Println("Working...") time.Sleep(500 * time.Millisecond) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) go doWork(ctx) time.Sleep(2 * time.Second) cancel() // stop the work time.Sleep(1 * time.Second) // wait to see cancellation }
Output
Working...
Working...
Working...
Working...
Work cancelled: context canceled
Common Pitfalls
- Not passing
context.Contextas the first parameter in functions that need it. - Ignoring the context cancellation signal and continuing work.
- Creating new root contexts inside functions instead of passing the existing one down.
- Using
context.TODO()in production instead of proper contexts.
go
package main import ( "context" "fmt" ) // Wrong: creating new root context inside function func doWorkWrong() { ctx := context.Background() // This ignores caller's context select { case <-ctx.Done(): fmt.Println("Cancelled") default: fmt.Println("Working") } } // Right: accept context as parameter func doWorkRight(ctx context.Context) { select { case <-ctx.Done(): fmt.Println("Cancelled") default: fmt.Println("Working") } } func main() { doWorkWrong() doWorkRight(context.Background()) }
Output
Working
Working
Quick Reference
Remember these key functions from the context package:
context.Background(): returns an empty root context.context.TODO(): placeholder context for unfinished code.context.WithCancel(parent): returns a context and a cancel function to stop work.context.WithTimeout(parent, duration): cancels context after timeout.context.WithDeadline(parent, time): cancels context at a specific time.
Key Takeaways
Always pass context.Context as the first argument to functions needing cancellation or deadlines.
Create root contexts with context.Background() or context.TODO() and pass them down.
Use context.WithCancel, WithTimeout, or WithDeadline to control cancellation.
Check ctx.Done() channel to stop work early when context is cancelled.
Avoid creating new root contexts inside functions; always accept and pass context.