Fiber

Express.js-like Go web framework. Popular among Node.js migrants with enhanced native support for streaming and WebSockets.

GoFrameworkWeb DevelopmentExpress.js-inspiredHigh Performancefasthttp

GitHub Overview

gofiber/fiber

⚡️ Express inspired web framework written in Go

Stars37,153
Watchers286
Forks1,825
Created:January 16, 2020
Language:Go
License:MIT License

Topics

expressexpressjsfastfiberflexibleframeworkfriendlygogolanghacktoberfesthacktoberfest2020nodejsperformancerest-apiweb

Star History

gofiber/fiber Star History
Data as of: 7/17/2025, 05:31 AM

Framework

Fiber

Overview

Fiber is a Go web framework inspired by Express.js. Built on top of the fast fasthttp engine, it provides an Express.js-like API to enhance development experience.

Details

Fiber was developed in 2019 as an Express.js-inspired web framework built on Go's high-speed HTTP library fasthttp. To reduce the learning cost for developers migrating from Node.js to Go, it recreates Express.js's user-friendly API and concepts in Go. With its zero-allocation design, it minimizes memory usage and achieves extremely high performance. It comes with comprehensive features including routing, middleware system, static file serving, template engines, WebSocket support, and rate limiting out of the box. It also provides React-like component systems and real-time communication features, comprehensively supporting the elements needed for modern web application development. However, it has constraints due to lack of compatibility with net/http, making some Go standard ecosystem tools unusable.

Pros and Cons

Pros

  • Express.js-like API: Familiar API design for Node.js developers
  • Ultra-fast Performance: Extremely high processing performance based on fasthttp
  • Zero Allocation: Memory-efficient design with low resource consumption
  • Rich Middleware: Comprehensive middleware for authentication, logging, CORS, compression, etc.
  • Easy Learning: Intuitive and understandable API design
  • WebSocket Support: Standard support for real-time communication features
  • Active Development: Active community and continuous feature additions

Cons

  • net/http Incompatibility: No compatibility with Go's standard HTTP library
  • Ecosystem Limitations: Some Go tools (gqlgen, go-swagger, etc.) cannot be used
  • Express Learning: Additional learning cost if unfamiliar with Express.js
  • Immutable Constraints: Values are not guaranteed to be immutable by default
  • Dependencies: Dependency on fasthttp library

Key Links

Code Examples

Hello World

package main

import (
    "log"
    "github.com/gofiber/fiber/v2"
)

func main() {
    // Create Fiber app instance
    app := fiber.New()

    // GET /hello route
    app.Get("/hello", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })

    // Start server
    log.Fatal(app.Listen(":3000"))
}

Routing and Parameters

package main

import (
    "log"
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    // Basic routes
    app.Get("/", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "message": "Welcome to Fiber API",
        })
    })

    // Path parameters
    app.Get("/users/:id", func(c *fiber.Ctx) error {
        userID := c.Params("id")
        return c.JSON(fiber.Map{
            "user_id": userID,
            "name":    "User " + userID,
        })
    })

    // Query parameters
    app.Get("/search", func(c *fiber.Ctx) error {
        query := c.Query("q")
        page := c.Query("page", "1") // Default value

        return c.JSON(fiber.Map{
            "query": query,
            "page":  page,
            "results": []string{"Result 1", "Result 2"},
        })
    })

    // Wildcards
    app.Get("/files/*", func(c *fiber.Ctx) error {
        filename := c.Params("*")
        return c.JSON(fiber.Map{
            "filename": filename,
            "path":     "/files/" + filename,
        })
    })

    // HTTP methods
    app.Post("/users", createUser)
    app.Put("/users/:id", updateUser)
    app.Delete("/users/:id", deleteUser)

    log.Fatal(app.Listen(":3000"))
}

func createUser(c *fiber.Ctx) error {
    return c.JSON(fiber.Map{"message": "User created"})
}

func updateUser(c *fiber.Ctx) error {
    id := c.Params("id")
    return c.JSON(fiber.Map{"message": "User " + id + " updated"})
}

func deleteUser(c *fiber.Ctx) error {
    id := c.Params("id")
    return c.JSON(fiber.Map{"message": "User " + id + " deleted"})
}

JSON Body Parsing

package main

import (
    "log"
    "github.com/gofiber/fiber/v2"
)

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

func main() {
    app := fiber.New()

    // JSON body parsing and validation
    app.Post("/users", func(c *fiber.Ctx) error {
        user := new(User)

        // Parse JSON body
        if err := c.BodyParser(user); err != nil {
            return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
                "error": "Failed to parse JSON",
            })
        }

        // Simple validation
        if user.Name == "" {
            return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
                "error": "Name is required",
            })
        }

        if user.Email == "" {
            return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
                "error": "Email is required",
            })
        }

        // User processing (database save, etc.)
        // ...

        return c.Status(fiber.StatusCreated).JSON(fiber.Map{
            "message": "User created successfully",
            "user":    user,
        })
    })

    // Form data parsing
    app.Post("/upload", func(c *fiber.Ctx) error {
        name := c.FormValue("name")
        file, err := c.FormFile("file")
        
        if err != nil {
            return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
                "error": "File upload error",
            })
        }

        return c.JSON(fiber.Map{
            "name":     name,
            "filename": file.Filename,
            "size":     file.Size,
        })
    })

    log.Fatal(app.Listen(":3000"))
}

Using Middleware

package main

import (
    "fmt"
    "log"
    "time"
    
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/cors"
    "github.com/gofiber/fiber/v2/middleware/logger"
    "github.com/gofiber/fiber/v2/middleware/recover"
    "github.com/gofiber/fiber/v2/middleware/limiter"
)

func main() {
    app := fiber.New()

    // Standard middleware
    app.Use(logger.New())    // Request logging
    app.Use(recover.New())   // Panic recovery
    app.Use(cors.New())      // CORS support

    // Rate limiting
    app.Use(limiter.New(limiter.Config{
        Max:        20,                      // 20 requests per minute
        Expiration: 1 * time.Minute,
        KeyGenerator: func(c *fiber.Ctx) string {
            return c.IP()
        },
        LimitReached: func(c *fiber.Ctx) error {
            return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{
                "error": "Rate limit reached",
            })
        },
    }))

    // Custom middleware
    app.Use(func(c *fiber.Ctx) error {
        fmt.Printf("Request: %s %s\n", c.Method(), c.Path())
        c.Set("X-Custom-Header", "Fiber API")
        return c.Next()
    })

    // Authentication middleware
    app.Use("/api", authMiddleware)

    // Public routes
    app.Get("/", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "message": "Fiber API Server",
        })
    })

    // Protected routes
    app.Get("/api/profile", func(c *fiber.Ctx) error {
        userID := c.Locals("userID")
        return c.JSON(fiber.Map{
            "user_id": userID,
            "message": "Authenticated user",
        })
    })

    log.Fatal(app.Listen(":3000"))
}

func authMiddleware(c *fiber.Ctx) error {
    token := c.Get("Authorization")
    
    if token == "" {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
            "error": "Authentication token required",
        })
    }

    // Token verification logic
    if token != "Bearer valid_token" {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
            "error": "Invalid token",
        })
    }

    // Store user info in local storage
    c.Locals("userID", "123")
    
    return c.Next()
}

Route Groups

package main

import (
    "log"
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/basicauth"
)

func main() {
    app := fiber.New()

    // Basic routes
    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Fiber API")
    })

    // API group (v1)
    v1 := app.Group("/api/v1")
    
    v1.Get("/users", func(c *fiber.Ctx) error {
        return c.JSON([]fiber.Map{
            {"id": 1, "name": "User 1"},
            {"id": 2, "name": "User 2"},
        })
    })

    v1.Get("/posts", func(c *fiber.Ctx) error {
        return c.JSON([]fiber.Map{
            {"id": 1, "title": "Post 1"},
            {"id": 2, "title": "Post 2"},
        })
    })

    // Admin group (Basic auth)
    admin := app.Group("/admin")
    admin.Use(basicauth.New(basicauth.Config{
        Users: map[string]string{
            "admin": "secret",
        },
    }))

    admin.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Admin Dashboard")
    })

    admin.Get("/users", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "message": "All users management",
            "users":   []string{"admin", "user1", "user2"},
        })
    })

    // Nested groups
    api := app.Group("/api")
    v1API := api.Group("/v1")
    
    // Group level middleware
    v1API.Use(func(c *fiber.Ctx) error {
        c.Set("API-Version", "v1.0")
        return c.Next()
    })

    v1API.Get("/info", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "version": "1.0",
            "status":  "active",
        })
    })

    log.Fatal(app.Listen(":3000"))
}

Error Handling

package main

import (
    "errors"
    "log"
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New(fiber.Config{
        // Custom error handler
        ErrorHandler: func(c *fiber.Ctx, err error) error {
            // Default error code
            code := fiber.StatusInternalServerError

            // Get code from Fiber error if it's a Fiber error
            if e, ok := err.(*fiber.Error); ok {
                code = e.Code
            }

            // Custom error response
            return c.Status(code).JSON(fiber.Map{
                "error":   true,
                "message": err.Error(),
                "code":    code,
            })
        },
    })

    // Normal route
    app.Get("/", func(c *fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "message": "Normal response",
        })
    })

    // Route returning 400 error
    app.Get("/bad-request", func(c *fiber.Ctx) error {
        return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
    })

    // Custom error
    app.Get("/custom-error", func(c *fiber.Ctx) error {
        return errors.New("Custom error occurred")
    })

    // Catch 404 errors
    app.Use(func(c *fiber.Ctx) error {
        return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
            "error":   true,
            "message": "Page not found",
            "code":    404,
        })
    })

    log.Fatal(app.Listen(":3000"))
}

WebSocket Connection

package main

import (
    "log"
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/contrib/websocket"
)

func main() {
    app := fiber.New()

    // WebSocket upgrade middleware
    app.Use("/ws", func(c *fiber.Ctx) error {
        if websocket.IsWebSocketUpgrade(c) {
            c.Locals("allowed", true)
            return c.Next()
        }
        return fiber.ErrUpgradeRequired
    })

    // WebSocket endpoint
    app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
        // Get connection info
        log.Println("WebSocket connection:", c.Params("id"))
        log.Println("Allowed:", c.Locals("allowed"))

        var (
            mt  int
            msg []byte
            err error
        )

        for {
            // Read message
            if mt, msg, err = c.ReadMessage(); err != nil {
                log.Println("Read error:", err)
                break
            }

            log.Printf("Received: %s", msg)

            // Echo back
            if err = c.WriteMessage(mt, msg); err != nil {
                log.Println("Write error:", err)
                break
            }
        }
    }))

    // Static files (for WebSocket client)
    app.Static("/", "./static")

    log.Println("Server started: http://localhost:3000")
    log.Println("WebSocket: ws://localhost:3000/ws/123")
    log.Fatal(app.Listen(":3000"))
}