---
title: "GN002 – Use c.Request.Context(), Not context.Background()"
impact: medium
impactDescription: "context.Background() ignores client disconnects and request deadlines; c.Request.Context() propagates cancellation automatically."
tags: [go, gin, context, correctness]
---

# GN002 – Use `c.Request.Context()` Not `context.Background()`

## Rule

When passing a context to database calls, external HTTP requests, or any `ctx context.Context` parameter inside a Gin handler, always use `c.Request.Context()`. Never create a fresh `context.Background()` inside a handler.

## Why

`c.Request.Context()` is derived from the HTTP request and carries the client's cancellation signal. If the client disconnects mid-request, the context is cancelled and all downstream work (DB queries, gRPC calls) is cancelled too — preventing wasted compute. `context.Background()` is never cancelled and leaks work after the client is gone.

## Wrong

```go
func (h *OrderHandler) Create(c *gin.Context) {
    var req CreateOrderRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    // ❌ context.Background() — ignores client disconnect and server deadlines
    order, err := h.service.CreateOrder(context.Background(), req)
    if err != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusCreated, order)
}
```

## Correct

```go
func (h *OrderHandler) Create(c *gin.Context) {
    var req CreateOrderRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    // ✅ propagates request lifetime, deadline, and cancellation
    ctx := c.Request.Context()
    order, err := h.service.CreateOrder(ctx, req)
    if err != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusCreated, order)
}
```

## Notes

- Extract the context once: `ctx := c.Request.Context()` at the top of the handler body.
- Do **not** store this context in a struct field — contexts must flow through function arguments.
- If you need a timeout shorter than the request's own deadline: `ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second); defer cancel()`.
- See GN010 for the rule about not storing Gin context in goroutines.
