π§ Go Context
Fiber Context as context.Contextβ
Fiber's Ctx implements Go's
context.Context interface.
You can pass c directly to functions that expect a context.Context
without adapters, but only to read values from it. Ctx is a context that can
never be canceled: Deadline, Done, and Err always report no deadline,
nil, and nil, whatever you set with c.SetContext. For cancellation and
deadlines, use c.Context().
The fiber.Ctx instance is only valid within the lifetime of the handler.
It is reused for subsequent requests, so avoid storing c or using it in
goroutines that outlive the handler. For asynchronous work, call
c.Context() inside the handler to obtain a context.Context that can safely
be used after the handler returns. By default, this returns context.Background()
unless a custom context was provided with c.SetContext. The context outlives
the handler, but a string you read from the request does not unless
Immutable is set: copy such a value inside the
handler before you start the goroutine, as Context Helpers
shows.
func doSomething(ctx context.Context) {
// ... your logic here
}
app.Get("/", func(c fiber.Ctx) error {
doSomething(c) // c satisfies context.Context
return nil
})
Using context outside the handlerβ
fiber.Ctx is recycled after each request. If you need a context that lives
longerβfor example, for work performed in a new goroutineβobtain it with
c.Context() before returning from the handler.
app.Get("/job", func(c fiber.Ctx) error {
ctx := c.Context()
go performAsync(ctx)
return c.SendStatus(fiber.StatusAccepted)
})
You can customize the base context by calling c.SetContext before
requesting it. This changes what c.Context() returns for the rest of the
request; it does not make c itself cancelable.
app.Get("/job", func(c fiber.Ctx) error {
c.SetContext(context.WithValue(context.Background(), "requestID", "123"))
ctx := c.Context()
go performAsync(ctx)
return nil
})
Retrieving Valuesβ
Ctx.Value is backed by Locals.
Values stored with c.Locals are accessible through Value or
standard context.WithValue helpers.
app.Get("/", func(c fiber.Ctx) error {
c.Locals("role", "admin")
role := c.Value("role") // returns "admin"
return c.SendString(role.(string))
})
Working with RequestCtxβ
The underlying fasthttp.RequestCtx
can be accessed via c.RequestCtx().
This exposes low-level APIs and a context.Context implementation of its own.
app.Get("/raw", func(c fiber.Ctx) error {
fctx := c.RequestCtx()
// use fasthttp APIs directly
fctx.Response.Header.Set("X-Engine", "fasthttp")
return nil
})
fasthttp.RequestCtx satisfies the context.Context interface itself.
Deadline always reports no deadline. Done closes only when the server
shuts down, and Err then returns context.Canceled. Note that this is the
fasthttp.RequestCtx, not Fiber's Ctx, whose Done is always nil.
Done does not fire when an individual client disconnects. To stop a
long-running handler at a deadline, wrap c.Context() with
context.WithTimeout as shown below.
Context Helpersβ
Fiber and its middleware expose a number of helper functions that retrieve request-scoped values from the context.
Middleware stores these values with fiber.StoreInContext, and the helpers
read them back with fiber.ValueFromContext. The helpers accept a fiber.Ctx
as well as a plain context.Context.
StoreInContext always writes to c.Locals(). It also copies the value into
the context returned by c.Context() when
PassLocalsToContext is enabled, which
it is not by default. Reading from c itself therefore always works, but a
helper called with c.Context(), as you would in code that only receives a
context.Context, finds the value only when that setting is on:
app := fiber.New(fiber.Config{PassLocalsToContext: true})
app.Use(requestid.New())
app.Get("/job", func(c fiber.Ctx) error {
ctx := c.Context() // take it inside the handler
// empty unless PassLocalsToContext is true; copy it, see the caution below
id := strings.Clone(requestid.FromContext(ctx))
go func() {
_ = id
}()
return c.SendStatus(fiber.StatusAccepted)
})
Read what you need from the context inside the handler and hand the goroutine a copy. A retained context keeps working after the handler returns, but what it holds may not stay valid:
- A string that comes from the request, such as the request ID when the client sent one or the key that
keyauthextracted, points into a buffer that fasthttp reuses for the next request on the connection. UnlessImmutableis set, a goroutine that reads it later can see another request's ID or token. Copy it withstrings.Clonebefore you hand it over; see Zero Allocation. - A context you keep stops resolving a session when its request ends:
session.FromContextreturnsnilfor it from then on, so a goroutine that outlives the handler cannot reach the session, and never another user's. The*session.Middlewareit returned while the request was running is only valid until the handler returns, so do not hand that pointer to a goroutine that may outlive the handler either. Read what you need inside the handler, for example the session ID, and hand that to the goroutine; see the Store Pattern for background work on a session.
Use the same pair for your own values:
type userKey struct{}
fiber.StoreInContext(c, userKey{}, "john")
name, ok := fiber.ValueFromContext[string](c, userKey{})
Request IDβ
The RequestID middleware stores the generated identifier in the context.
Use requestid.FromContext to read it later.
app.Use(requestid.New())
app.Get("/", func(c fiber.Ctx) error {
id := requestid.FromContext(c)
return c.SendString(id)
})
CSRFβ
The CSRF middleware provides helpers to fetch the token or the handler attached to the current context.
app.Use(csrf.New())
app.Get("/form", func(c fiber.Ctx) error {
token := csrf.TokenFromContext(c)
return c.SendString(token)
})
app.Post("/logout", func(c fiber.Ctx) error {
handler := csrf.HandlerFromContext(c)
if handler != nil {
// Invalidate the token on logout
_ = handler.DeleteToken(c)
}
// ... other logout logic
return c.SendString("Logged out")
})
Sessionβ
Sessions are stored on the context and can be retrieved via
session.FromContext.
app.Use(session.New())
app.Get("/", func(c fiber.Ctx) error {
sess := session.FromContext(c)
count := sess.Get("visits")
return c.JSON(fiber.Map{"visits": count})
})
Basic Authenticationβ
After successful authentication, the username is available with
basicauth.UsernameFromContext. Passwords in Users must be pre-hashed.
app.Use(basicauth.New(basicauth.Config{
Users: map[string]string{
// "secret" hashed using SHA-256
"admin": "{SHA256}K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=",
},
}))
app.Get("/", func(c fiber.Ctx) error {
user := basicauth.UsernameFromContext(c)
return c.SendString(user)
})
Key Authenticationβ
For API key authentication, the extracted token is stored in the
context and accessible via keyauth.TokenFromContext. The middleware requires
a Validator, and reads the key from the Authorization: Bearer <key> header
unless you set another Extractor.
app.Use(keyauth.New(keyauth.Config{
Validator: func(c fiber.Ctx, key string) (bool, error) {
return subtle.ConstantTimeCompare([]byte(key), []byte("secret")) == 1, nil
},
}))
app.Get("/", func(c fiber.Ctx) error {
token := keyauth.TokenFromContext(c)
return c.SendString(token)
})
Using context.WithValue and Friendsβ
Standard helpers such as context.WithValue, context.WithTimeout, or
context.WithCancel can wrap the request context when needed. Derive them
from c.Context(), not from c: c can never be canceled, so a context
derived from it would never inherit a deadline or a cancellation.
app.Get("/job", func(c fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), 5*time.Second)
defer cancel()
// pass ctx to async operations that honor cancellation
if err := doWork(ctx); err != nil {
return err
}
return c.SendStatus(fiber.StatusOK)
})
Context Cancellation with Goroutines in Fiberβ
When starting asynchronous work inside a handler, Fiber does not cancel the base fiber.Ctx automatically.
By wrapping the request context with context.WithTimeout, you can create a derived context that honors deadlines and cancellation signals.
The goroutine checks ctx.Done() before sending a result.
If the deadline elapses, the goroutine exits early and avoids leaking resources.
The handler then waits for either:
- a result from the goroutine, or
- the
context timeout(which returns a 504 Gateway Timeout)
This pattern ensures that long-running operations (database queries, external API calls, background tasks) do not continue running after the request has ended.
func Handler(c fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), 2*time.Second)
defer cancel()
resultChan := make(chan string, 1)
go func() {
select {
case <-time.After(3 * time.Second):
select {
case <-ctx.Done():
return
case resultChan <- "done":
}
case <-ctx.Done():
return
}
}()
select {
case res := <-resultChan:
return c.SendString(res)
case <-ctx.Done():
return c.Status(fiber.StatusGatewayTimeout).SendString("timeout")
}
}
This approach provides safe cancellation semantics for goroutine-based work while allowing you to integrate Fiber handlers with context-aware APIs.
Summaryβ
fiber.Ctxsatisfiescontext.Contextbut itsDeadline,Done, andErrmethods are currently no-ops.RequestCtxexposes the rawfasthttpcontext. ItsDonechannel closes only on server shutdown, not on client disconnect.- Use
fiber.StoreInContext(c, key, value)to store request-scoped values inc.Locals()and, whenfiber.Config.PassLocalsToContextis enabled, inc.Context()as well, so they are available through either API. - Middleware helpers like
requestid.FromContextorsession.FromContextmake it easy to retrieve request-scoped data. Copy a string that comes from the request, or setImmutable, before a goroutine keeps it. - Standard helpers such as
context.WithTimeoutshould wrapc.Context(), notfiber.Ctx, to create derived contexts that honor deadlines and can outlive the handler. fiber.Config.PassLocalsToContextcontrols whether Fiber context helpers also propagate values into the requestcontext.Contextfor Fiber-backed contexts when usingStoreInContext. It defaults tofalsefor backward compatibility, whileValueFromContextkeeps reading fromc.Locals().- Use
c.Context()to obtain acontext.Contextthat can outlive the handler, andc.SetContext()to customize it with additional values or deadlines.
With these tools, you can seamlessly integrate Fiber applications with Go's context-based APIs and manage request-scoped data effectively.