Skip to main content

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

Build docs developers (and LLMs) love