# Context Values and the Rules — Go Concurrency Patterns

Source: https://www.skillbyai.com/en/go-concurrency/gc-ctx-values

> Conventions that keep contexts predictable.

## First parameter, not a struct field

The conventions from the `context` package docs: pass a context explicitly as the **first parameter**, conventionally named `ctx`; **do not store contexts inside structs** (a struct outlives the request and hides which call the context belongs to); never pass a nil context (use `context.TODO()` if unsure). `context.WithValue` attaches **request-scoped** data that crosses API boundaries, such as a request ID, trace span or authenticated user, not optional function parameters or dependencies like loggers and database handles. Use an **unexported key type** so that keys from different packages cannot collide, and provide typed helper functions to set and read the value. Contexts are immutable and safe for use by multiple goroutines.

## A typed request-ID helper

An unexported key type prevents collisions.

```go
package reqid

import "context"

type ctxKey struct{} // unexported: no other package can build this key

func With(ctx context.Context, id string) context.Context {
	return context.WithValue(ctx, ctxKey{}, id)
}

func From(ctx context.Context) (string, bool) {
	id, ok := ctx.Value(ctxKey{}).(string)
	return id, ok
}

// Usage in a handler:
//   ctx := reqid.With(r.Context(), newID())
//   svc.PlaceOrder(ctx, order) // ctx is always the first parameter
```

## If the function needs it to work, make it a parameter

Values hidden in a context are invisible in signatures and unchecked by the compiler. Keep them for cross-cutting metadata that most functions merely pass along.

**Quiz:** Which use of context.WithValue follows the documented guidance?

- [x] Carrying a request ID through a call chain
- [ ] Passing the database connection pool
- [ ] Passing an optional retry count to one function
- [ ] Storing the context in a long-lived service struct

*Answer:* Carrying a request ID through a call chain. Context values are for request-scoped data that crosses API boundaries.
