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.
Rewrite middleware for Fiber rewrites the URL path based on provided rules. Unlike redirect middleware, rewrite modifies the request path internally without sending a redirect response to the client.
Signatures
func New(config ...Config) fiber.Handler
Usage
import (
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/rewrite"
)
Basic Usage
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/old": "/new",
},
}))
Pattern Matching with Wildcards
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/old": "/new",
"/api/*": "/$1",
"/js/*": "/public/javascript/$1",
"/users/*/orders/*": "/user/$1/order/$2",
},
}))
API Versioning
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/api/v1/*": "/v1/$1",
"/api/v2/*": "/v2/$1",
},
}))
// Requests to /api/v1/users internally route to /v1/users
app.Get("/v1/:resource", v1Handler)
app.Get("/v2/:resource", v2Handler)
Skip Specific Paths
app.Use(rewrite.New(rewrite.Config{
Next: func(c fiber.Ctx) bool {
// Skip rewriting for admin routes
return strings.HasPrefix(c.Path(), "/admin")
},
Rules: map[string]string{
"/old/*": "/new/$1",
},
}))
Configuration
Next
func(fiber.Ctx) bool
default:"nil"
Defines a function to skip this middleware when it returns true.
Rules
map[string]string
required
Defines the URL path rewrite rules. The values captured in asterisk wildcards can be retrieved by index e.g. $1, $2 and so on.Example rules:
"/old": "/new" - Simple rewrite
"/api/*": "/$1" - Capture and reuse path
"/js/*": "/public/javascript/$1" - Add prefix
"/users/*/orders/*": "/user/$1/order/$2" - Multiple captures
Default Config
The rewrite middleware does not have default configuration values. Rules must be explicitly provided.
Common Use Cases
Clean URLs
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/products/:id": "/p/:id",
"/categories/:name": "/c/:name",
},
}))
// Users see: /products/123
// Internally routes to: /p/123
app.Get("/p/:id", productHandler)
Static File Organization
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/static/js/*": "/assets/javascript/$1",
"/static/css/*": "/assets/stylesheets/$1",
"/static/img/*": "/assets/images/$1",
},
}))
app.Static("/assets", "./public")
Multi-Tenancy
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/:tenant/api/*": "/api/$1",
},
}))
app.Use(func(c fiber.Ctx) error {
tenant := c.Params("tenant")
c.Locals("tenant", tenant)
return c.Next()
})
app.Get("/api/users", func(c fiber.Ctx) error {
tenant := c.Locals("tenant").(string)
// Handle request for specific tenant
return c.JSON(users)
})
Backward Compatibility
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/legacy/user/*": "/api/v2/users/$1",
"/legacy/product/*": "/api/v2/products/$1",
},
}))
// Old URLs still work, internally using new routes
app.Get("/api/v2/users/:id", userHandler)
Language Routing
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/en/*": "/$1",
"/es/*": "/$1",
"/fr/*": "/$1",
},
}))
app.Use(func(c fiber.Ctx) error {
// Extract language from original path
path := c.OriginalURL()
if strings.HasPrefix(path, "/en") {
c.Locals("lang", "en")
} else if strings.HasPrefix(path, "/es") {
c.Locals("lang", "es")
}
return c.Next()
})
Microservice Routing
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/api/users/*": "/users-service/$1",
"/api/products/*": "/products-service/$1",
"/api/orders/*": "/orders-service/$1",
},
}))
// Route to different service handlers
app.All("/users-service/*", proxyToUsersService)
app.All("/products-service/*", proxyToProductsService)
Best Practices
Order Matters
// More specific rules should be defined first
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/api/v2/admin/*": "/admin/v2/$1", // Specific
"/api/v2/*": "/v2/$1", // General
},
}))
Use with Router Groups
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/api/*": "/$1",
},
}))
api := app.Group("/")
api.Get("/users", getUsers) // Accessed via /api/users
api.Post("/users", createUser) // Accessed via /api/users
Combine with Other Middleware
// Rewrite must come before route registration
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/v1/*": "/api/v1/$1",
},
}))
// Other middleware after rewrite
app.Use(logger.New())
app.Use(cors.New())
Testing Rewrite Rules
app.Use(rewrite.New(rewrite.Config{
Rules: map[string]string{
"/test/*": "/actual/$1",
},
}))
app.Get("/actual/:path", func(c fiber.Ctx) error {
return c.SendString("Path: " + c.Params("path"))
})
// Test: GET /test/hello -> "Path: hello"
Notes
- Rewrite happens internally - the client is not aware of the URL change
- Wildcards (
*) in rules capture path segments that can be referenced as $1, $2, etc.
- Rewrite modifies
c.Path() but c.OriginalURL() remains unchanged
- The middleware uses regular expressions internally for pattern matching
- Query parameters and fragments are preserved during rewriting
- Use rewrite for internal routing logic; use redirect for external URL changes