Skip to main content
A context.Context carries deadlines, cancellation signals, and other request-scoped values across API boundaries and goroutines. This example demonstrates using context with HTTP servers to control cancellation.

Context in HTTP Servers

HTTP servers are useful for demonstrating the usage of context.Context for controlling cancellation. The net/http machinery creates a context for each request automatically.
package main

import (
	"fmt"
	"net/http"
	"time"
)

func hello(w http.ResponseWriter, req *http.Request) {
	// A `context.Context` is created for each request by
	// the `net/http` machinery, and is available with
	// the `Context()` method.
	ctx := req.Context()
	fmt.Println("server: hello handler started")
	defer fmt.Println("server: hello handler ended")

	// Wait for a few seconds before sending a reply to the
	// client. This could simulate some work the server is
	// doing. While working, keep an eye on the context's
	// `Done()` channel for a signal that we should cancel
	// the work and return as soon as possible.
	select {
	case <-time.After(10 * time.Second):
		fmt.Fprintf(w, "hello\n")
	case <-ctx.Done():
		// The context's `Err()` method returns an error
		// that explains why the `Done()` channel was
		// closed.
		err := ctx.Err()
		fmt.Println("server:", err)
		internalError := http.StatusInternalServerError
		http.Error(w, err.Error(), internalError)
	}
}

func main() {
	// As before, we register our handler on the "/hello"
	// route, and start serving.
	http.HandleFunc("/hello", hello)
	http.ListenAndServe(":8090", nil)
}

How Context Cancellation Works

1

Get Request Context

Call req.Context() to get the context associated with the HTTP request.
2

Monitor Done Channel

Use the ctx.Done() channel in a select statement to detect when the request is cancelled.
3

Handle Cancellation

When ctx.Done() closes, call ctx.Err() to get the reason (e.g., timeout, client disconnect).
4

Clean Up

Stop ongoing work and return an appropriate error response to the client.

The Select Pattern

The select statement is key to responding to context cancellation:
select {
case <-time.After(10 * time.Second):
	// Normal completion after work is done
	fmt.Fprintf(w, "hello\n")
case <-ctx.Done():
	// Request was cancelled
	err := ctx.Err()
	http.Error(w, err.Error(), http.StatusInternalServerError)
}
This pattern allows your server to gracefully handle client disconnections and timeouts, preventing wasted resources on abandoned requests.

When Context Gets Cancelled

When a client closes the connection (e.g., hitting Ctrl+C on a curl request), the context is automatically cancelled.
If the server or client has configured a request timeout, the context will be cancelled when the deadline is reached.
You can create contexts with explicit cancellation functions using context.WithCancel() for custom cancellation logic.

Running the Example

# Run the server in the background.
$ go run context.go &

# Simulate a client request to `/hello`, hitting
# Ctrl+C shortly after starting to signal
# cancellation.
$ curl localhost:8090/hello
server: hello handler started
^C
server: context canceled
server: hello handler ended
When you cancel the request with Ctrl+C, the server detects the cancellation through the context and stops processing immediately.

Best Practices

Always Check Context

Long-running operations should regularly check ctx.Done() to respect cancellation.

Pass Context Down

Pass the context to any functions or goroutines that do work on behalf of the request.

Don't Store Contexts

Contexts are request-scoped. Never store them in structs or use them beyond the request lifecycle.

Use Context Values Sparingly

Only use context values for request-scoped data like authentication tokens, not for passing optional parameters.

Next Steps

HTTP Server

Learn more about building HTTP servers

HTTP Client

Make HTTP requests with context support

Build docs developers (and LLMs) love