Documentation Index Fetch the complete documentation index at: https://mintlify.com/gofiber/fiber/llms.txt
Use this file to discover all available pages before exploring further.
Middleware functions are functions that have access to the request context and execute sequentially in a chain. They can modify the request, perform authentication, log data, or terminate the request early.
How Middleware Works
Middleware executes in the order it’s registered, forming a chain where each middleware can:
Execute code before the route handler
Call c.Next() to pass control to the next middleware/handler
Execute code after the next handler returns
Terminate the request early without calling c.Next()
app := fiber . New ()
// Middleware 1
app . Use ( func ( c fiber . Ctx ) error {
fmt . Println ( "Before request" )
// Pass control to next middleware
err := c . Next ()
fmt . Println ( "After request" )
return err
})
// Route handler
app . Get ( "/" , func ( c fiber . Ctx ) error {
fmt . Println ( "Handler" )
return c . SendString ( "Hello" )
})
// Output order:
// Before request
// Handler
// After request
The Next() Function
The c.Next() function passes control to the next middleware or route handler in the stack:
app . Use ( func ( c fiber . Ctx ) error {
fmt . Println ( "Middleware 1 - Before" )
// Execute next middleware/handler
if err := c . Next (); err != nil {
return err
}
fmt . Println ( "Middleware 1 - After" )
return nil
})
app . Use ( func ( c fiber . Ctx ) error {
fmt . Println ( "Middleware 2" )
return c . Next ()
})
app . Get ( "/" , func ( c fiber . Ctx ) error {
fmt . Println ( "Route Handler" )
return c . SendString ( "Response" )
})
// Output:
// Middleware 1 - Before
// Middleware 2
// Route Handler
// Middleware 1 - After
Without Next()
If you don’t call c.Next(), the request terminates and subsequent middleware/handlers don’t execute:
app . Use ( func ( c fiber . Ctx ) error {
// Check authentication
if c . Get ( "Authorization" ) == "" {
return c . Status ( 401 ). SendString ( "Unauthorized" )
// c.Next() is NOT called - request ends here
}
return c . Next ()
})
app . Get ( "/protected" , func ( c fiber . Ctx ) error {
// Only executes if authentication passes
return c . SendString ( "Secret data" )
})
Global Middleware
Global middleware applies to all routes:
app := fiber . New ()
// Applies to all routes
app . Use ( func ( c fiber . Ctx ) error {
fmt . Println ( "Global middleware" )
return c . Next ()
})
app . Get ( "/users" , userHandler )
app . Get ( "/posts" , postHandler )
// Both routes execute the global middleware
Path-Specific Middleware
Apply middleware to specific paths or path prefixes:
// Middleware for /api/* routes only
app . Use ( "/api" , func ( c fiber . Ctx ) error {
fmt . Println ( "API middleware" )
return c . Next ()
})
app . Get ( "/api/users" , userHandler ) // Executes middleware
app . Get ( "/about" , aboutHandler ) // Does NOT execute middleware
Multiple Paths
Apply middleware to multiple specific paths:
app . Use ([] string { "/api" , "/admin" }, func ( c fiber . Ctx ) error {
fmt . Println ( "Protected routes" )
return c . Next ()
})
Route-Level Middleware
Attach middleware directly to specific routes:
func authMiddleware ( c fiber . Ctx ) error {
if c . Get ( "Authorization" ) == "" {
return c . Status ( 401 ). SendString ( "Unauthorized" )
}
return c . Next ()
}
// Multiple handlers - executed in order
app . Get ( "/protected" , authMiddleware , func ( c fiber . Ctx ) error {
return c . SendString ( "Protected resource" )
})
// Chain multiple middleware
app . Post ( "/users" ,
validateInput ,
checkPermissions ,
createUserHandler ,
)
Middleware Execution Order
Middleware executes in this order:
Global middleware (registered with app.Use())
Group middleware (registered on route groups)
Route-level middleware (passed to route methods)
Route handler
app . Use ( func ( c fiber . Ctx ) error {
fmt . Println ( "1. Global" )
return c . Next ()
})
api := app . Group ( "/api" , func ( c fiber . Ctx ) error {
fmt . Println ( "2. Group" )
return c . Next ()
})
api . Get ( "/users" ,
func ( c fiber . Ctx ) error {
fmt . Println ( "3. Route middleware" )
return c . Next ()
},
func ( c fiber . Ctx ) error {
fmt . Println ( "4. Handler" )
return c . SendString ( "Response" )
},
)
// Request to /api/users outputs:
// 1. Global
// 2. Group
// 3. Route middleware
// 4. Handler
Creating Custom Middleware
Basic Middleware
func Logger () fiber . Handler {
return func ( c fiber . Ctx ) error {
start := time . Now ()
// Process request
err := c . Next ()
// Log after response
fmt . Printf ( " %s %s - %v \n " ,
c . Method (),
c . Path (),
time . Since ( start ),
)
return err
}
}
app . Use ( Logger ())
Configurable Middleware
type RateLimiterConfig struct {
Max int
Duration time . Duration
}
func RateLimiter ( config RateLimiterConfig ) fiber . Handler {
// Initialize state
requests := make ( map [ string ] int )
return func ( c fiber . Ctx ) error {
ip := c . IP ()
// Check rate limit
if requests [ ip ] >= config . Max {
return c . Status ( 429 ). SendString ( "Too many requests" )
}
requests [ ip ] ++
// Reset after duration
time . AfterFunc ( config . Duration , func () {
requests [ ip ] = 0
})
return c . Next ()
}
}
app . Use ( RateLimiter ( RateLimiterConfig {
Max : 100 ,
Duration : time . Minute ,
}))
Common Middleware Patterns
Authentication
func RequireAuth ( c fiber . Ctx ) error {
token := c . Get ( "Authorization" )
if token == "" {
return fiber . NewError ( fiber . StatusUnauthorized , "Missing token" )
}
// Validate token
user , err := validateToken ( token )
if err != nil {
return fiber . NewError ( fiber . StatusUnauthorized , "Invalid token" )
}
// Store user in context
c . Locals ( "user" , user )
return c . Next ()
}
CORS
func CORS ( c fiber . Ctx ) error {
c . Set ( "Access-Control-Allow-Origin" , "*" )
c . Set ( "Access-Control-Allow-Methods" , "GET, POST, PUT, DELETE" )
c . Set ( "Access-Control-Allow-Headers" , "Content-Type, Authorization" )
// Handle preflight
if c . Method () == "OPTIONS" {
return c . SendStatus ( fiber . StatusNoContent )
}
return c . Next ()
}
app . Use ( CORS )
Request Validation
func ValidateJSON ( c fiber . Ctx ) error {
if c . Get ( "Content-Type" ) != "application/json" {
return fiber . NewError ( fiber . StatusBadRequest , "Content-Type must be application/json" )
}
return c . Next ()
}
app . Post ( "/api/users" , ValidateJSON , createUser )
Response Timing
func Timing ( c fiber . Ctx ) error {
start := time . Now ()
err := c . Next ()
duration := time . Since ( start )
c . Set ( "X-Response-Time" , duration . String ())
return err
}
app . Use ( Timing )
Error Handling in Middleware
Return errors from middleware to trigger the error handler:
app . Use ( func ( c fiber . Ctx ) error {
if someCondition {
// Return error - stops execution
return fiber . NewError ( fiber . StatusBadRequest , "Invalid request" )
}
return c . Next ()
})
// Custom error handler
app := fiber . New ( fiber . Config {
ErrorHandler : func ( c fiber . Ctx , err error ) error {
code := fiber . StatusInternalServerError
if e , ok := err .( * fiber . Error ); ok {
code = e . Code
}
return c . Status ( code ). JSON ( fiber . Map {
"error" : err . Error (),
})
},
})
RestartRouting
Restart routing from the beginning after modifying the path:
app . Use ( func ( c fiber . Ctx ) error {
// Rewrite path
if c . Path () == "/old-path" {
c . Path ( "/new-path" )
return c . RestartRouting ()
}
return c . Next ()
})
app . Get ( "/new-path" , handler )
Built-in Middleware
Fiber provides many built-in middleware packages:
Logger HTTP request/response logging
Recover Recover from panics
CORS Cross-Origin Resource Sharing
Compress Response compression
Timeout Request timeout handling
Session Session management
Best Practices
Always handle Next() errors
Check and return errors from c.Next() to ensure proper error propagation. if err := c . Next (); err != nil {
return err
}
Each middleware should have a single responsibility for maintainability. // Good: Separate concerns
app . Use ( LoggingMiddleware )
app . Use ( AuthMiddleware )
app . Use ( RateLimitMiddleware )
Use Locals for request-scoped data
Store data for the current request using c.Locals(). c . Locals ( "user" , user )
// Later: user := c.Locals("user")
Register middleware in the correct order - authentication before authorization, logging before everything. app . Use ( LoggerMiddleware ) // First
app . Use ( RecoverMiddleware ) // Second
app . Use ( AuthMiddleware ) // Third
See Also
Context Work with request and response data
Error Handling Handle errors in middleware
Grouping Apply middleware to route groups
Routing Define routes and handlers