Fiber — Architecture#

Architectural style#

Middleware-chain framework (Layered + Plugin-based Library)

Fiber is an HTTP web framework modeled on Express.js. Its architecture is a classic middleware pipeline layered on top of a high-performance HTTP engine (fasthttp). It is not a monolith or a microservice — it is a library that applications embed. The architectural style can be described as:

  1. Layered — there is a clear bottom-to-top stack: fasthttp engine → App/Router core → Ctx abstraction → Handler/Middleware chain → user code.
  2. Plugin-based — middleware is first-class. The 30+ bundled middleware packages all conform to the Handler = func(Ctx) error type and attach to the pipeline via app.Use() or method-specific route registration.
  3. Interface-driven extensibility — key abstractions (Ctx, Router, Storage, Service, Views, CustomBinder) are interfaces, allowing users to swap implementations without modifying the framework.

Evidence: app.requestHandler in router.go:315 is the fasthttp callback — it acquires a pooled Ctx, dispatches to app.next(), which walks the route/middleware stack. Every piece of user logic, middleware, and error recovery flows through this single handler function.

Component diagram (textual)#

┌─────────────────────────────────────────────────────────────┐
│                     User Application                        │
│  fiber.New() → app.Use(mw) → app.Get("/path", handler)      │
└────────────────────────┬────────────────────────────────────┘
                         │ registers routes/middleware
                         ▼
┌─────────────────────────────────────────────────────────────┐
│                        App (app.go)                         │
│  Config · Hooks · State · mountFields · pool (sync.Pool)    │
│  stack[][]*Route  ·  treeStack[]map[int][]*Route            │
└──────────┬──────────────────────────────────┬───────────────┘
           │ builds                           │ serves via
           ▼                                  ▼
┌──────────────────────┐          ┌───────────────────────────┐
│   Router (router.go) │          │    fasthttp.Server        │
│  Register routes     │          │  (listen.go / prefork.go) │
│  Build prefix tree   │          └───────────┬───────────────┘
│  app.next() dispatch │                      │ per-request
└──────────────────────┘                      ▼
                               ┌───────────────────────────────┐
                               │      DefaultCtx (ctx.go)      │
                               │  Wraps fasthttp.RequestCtx    │
                               │  Request/Response API         │
                               │  Binder · Redirect · Locals   │
                               └───────────┬───────────────────┘
                                           │ passed to
                                           ▼
                               ┌───────────────────────────────┐
                               │   Handler Chain               │
                               │  middleware[0] → middleware[1] │
                               │  → ... → route handler        │
                               └───────────────────────────────┘

Supporting subsystems:
  binder/       — request body/param binding (JSON, XML, CBOR, form, query, etc.)
  client/       — built-in HTTP client sharing serialization infrastructure
  middleware/*  — 30 production middleware packages (each self-contained)
  log/          — logging interface + default adapter
  internal/     — memory cache, storage interface wrapper (used by middleware)
  addon/retry/  — retry wrapper for handlers

Core components#

App#

  • Package: github.com/gofiber/fiber/v3 (app.go)
  • Responsibility: Central registry and runtime. Owns the route stack, fasthttp server, context pool, hooks, state, and mount/sub-app composition. Implements the Router interface for top-level route registration.
  • Key types: App, Config, ErrorHandler, Handler
  • Dependencies: fasthttp server, Hooks, State, mountFields, sync.Pool for DefaultCtx

Router / Route matching#

  • Package: github.com/gofiber/fiber/v3 (router.go)
  • Responsibility: Defines the Router interface, Route struct, and the core dispatch loop (app.next, app.nextCustom). Builds a 3-char prefix hash tree (treeStack) for fast route lookup. Handles middleware ordering, route registration/removal, and auto-HEAD generation.
  • Key types: Router (interface), Route, routeParser
  • Dependencies: App, fasthttp utils for unsafe string operations

DefaultCtx / Ctx interface#

  • Package: github.com/gofiber/fiber/v3 (ctx.go, ctx_interface_gen.go)
  • Responsibility: Wraps a fasthttp.RequestCtx and exposes Fiber’s request/response API. Implements context.Context and io.Writer. Holds route index, matched params, flash messages, and the Bind/Redirect helpers. Its interface (Ctx) is generated by ifacemaker from the DefaultCtx struct to ensure the interface stays in sync with the implementation.
  • Key types: DefaultCtx, Ctx (generated interface), CustomCtx (extension interface)
  • Dependencies: fasthttp, binder.Bind, Redirect

Binder subsystem#

  • Package: github.com/gofiber/fiber/v3/binder
  • Responsibility: Decoupled request-data binding for all content types (JSON, XML, CBOR, form, multipart, query string, header, cookie, URI params, msgpack). Each binder is a small struct implementing a shared interface. Exposed to users via ctx.Bind().
  • Key types: Binding interface, concrete binders per content type
  • Dependencies: encoding packages only; does not import the root fiber package (unidirectional dependency)

Hooks / lifecycle events#

  • Package: github.com/gofiber/fiber/v3 (hooks.go)
  • Responsibility: Provides an observable lifecycle: OnRoute, OnName, OnGroup, OnListen, OnPreStartup, OnPostStartup, OnPreShutdown, OnPostShutdown, OnFork, OnMount. Each hook slot is a slice of typed function callbacks registered by user code.
  • Key types: Hooks, 11 handler type aliases
  • Dependencies: App, log/

Services / managed lifecycle#

  • Package: github.com/gofiber/fiber/v3 (services.go)
  • Responsibility: Provides a Service interface (Start/State/Terminate/String) for wiring long-running dependencies (databases, caches, etc.) into the app lifecycle. Services are started before the server begins accepting requests and terminated on graceful shutdown. Their runtime state is tracked in App.state.
  • Key types: Service (interface)
  • Dependencies: State, context

State#

  • Package: github.com/gofiber/fiber/v3 (state.go)
  • Responsibility: App-level key/value store for arbitrary shared data across handlers. Also tracks which Service instances have been started. Provides a type-safe Set[T]/Get[T] generic API.
  • Key types: State
  • Dependencies: none beyond stdlib

Listen / prefork#

  • Package: github.com/gofiber/fiber/v3 (listen.go, prefork.go)
  • Responsibility: Creates and configures the fasthttp.Server, binds to TCP/Unix sockets, handles TLS (including Let’s Encrypt autocert and mTLS), prints the startup banner, triggers lifecycle hooks, and manages graceful shutdown. The prefork path spawns child processes using SO_REUSEPORT to saturate multiple CPU cores.
  • Key types: ListenConfig
  • Dependencies: fasthttp.Server, autocert, tls, lifecycle hooks

Middleware packages (30+)#

  • Package: github.com/gofiber/fiber/v3/middleware/*
  • Responsibility: Self-contained HTTP middleware packages — each exposes a New(config ...Config) fiber.Handler factory. They depend on the root fiber package for Ctx, Handler, App, and Storage types but are never imported by the core.
  • Key types: per-package Config + New() function; some use internal/storage for pluggable backends.

HTTP Client#

  • Package: github.com/gofiber/fiber/v3/client
  • Responsibility: A full HTTP client (request builder, response, cookie jar, transport, lifecycle hooks) that shares serialization codecs with the server. Not required for server usage; provides a symmetric API experience.
  • Key types: Client, Request, Response
  • Dependencies: fasthttp for HTTP transport

Data flow#

Typical HTTP request lifecycle:

1. net.Listener accepts TCP connection → fasthttp.Server reads request bytes

2. fasthttp.Server calls app.requestHandler(rctx *fasthttp.RequestCtx)

3. app.requestHandler:
   a. acquires DefaultCtx from sync.Pool (zero-allocation hot path)
   b. wraps rctx in DefaultCtx (or CustomCtx if configured)
   c. checks for flash cookies (redirects with messages)
   d. calls app.next(ctx) to walk the route/middleware stack

4. app.next (router.go:115):
   a. looks up the per-method route bucket from treeStack using
      a 3-char prefix hash of the path
   b. iterates routes in registration order:
      - calls route.match() for path + param extraction
      - if matched: executes route.Handlers[0](ctx), returns
   c. handler calls ctx.Next() → app.next() continues down the chain
   d. last handler returns nil → control unwinds up the chain

5. Any non-nil error propagates to app.config.ErrorHandler(ctx, err)

6. DefaultCtx released back to sync.Pool via defer app.ReleaseCtx(ctx)

Concrete example — authenticated JSON API:

Request →
  [1] recover middleware (catches panics)
  [2] cors middleware (sets CORS headers)
  [3] keyauth middleware (validates Bearer token via validator func)
  [4] requestid middleware (attaches X-Request-ID)
  [5] route handler (reads JSON body via ctx.Bind().JSON(&dto), calls service, returns ctx.JSON(result))
← Response

Initialization / Bootstrap#

fiber.New(config ...Config)               // app.go:543
  ├── allocate App struct
  ├── create sync.Pool { New: NewDefaultCtx }
  ├── newHooks(app)                        // hooks.go
  ├── newMountFields(app)                  // mount.go
  ├── newState()                           // state.go
  ├── apply config defaults (body limit, codecs, colors, methods)
  ├── build app.stack[][]*Route  (per HTTP method)
  ├── build app.treeStack[]map[int][]*Route
  └── app.init() — registers internal server-sent events handler if needed

app.Use(mw...) / app.Get(path, handler)   // router.go:register
  └── appends *Route to app.stack[method]
      sets routesRefreshed = true

app.Listen(addr, ListenConfig{})          // listen.go:172
  ├── configure TLS / autocert
  ├── BeforeServeFunc hook (if set)
  ├── app.startupProcess():
  │     ├── app.buildTree()                // constructs treeStack from stack
  │     ├── app.ensureAutoHeadRoutes()
  │     ├── app.initServices()             // starts Service instances
  │     ├── execute OnListen hooks
  │     └── print startup banner
  ├── net.Listen(network, addr)
  ├── fasthttp.Server.Serve(listener)     // blocking
  └── on SIGINT/SIGTERM or GracefulContext cancel:
        app.hooks OnPreShutdown
        fasthttp.Server.ShutdownWithContext
        app.shutdownServices()
        app.hooks OnPostShutdown

Dependency injection: Manual only. There is no Wire/Dig/Fx. Users wire dependencies through closures passed as handlers, or by storing shared objects in app.state / app.config.Services. The Service interface is a lightweight lifecycle pattern, not a DI container.

Configuration#

Configuration is a single flat struct (fiber.Config) passed to fiber.New(). There is no Viper, no env binding, no file parsing — Fiber is a library, so it delegates config loading to the user. Key configuration surface:

  • Serialization codecs: JSONEncoder/JSONDecoder, MsgPackEncoder/MsgPackDecoder, CBOREncoder/CBORDecoder, XMLEncoder/XMLDecoder — all swappable via function fields, enabling sonic/jsoniter/etc.
  • Template engine: Views interface — pluggable renderer (html/template, pug, jet, etc.)
  • Router behavior: StrictRouting, CaseSensitive, UnescapePath, DisableHeadAutoRegister
  • Error handler: ErrorHandler — global error centralization point
  • Server limits: BodyLimit, Concurrency, ReadTimeout, WriteTimeout
  • Services: Services []Service — lifecycle-managed dependencies
  • TLS is configured at listen time via ListenConfig, not Config, keeping the app struct decoupled from transport concerns.

Key design decisions#

  1. fasthttp as the HTTP engine. Fiber was purpose-built on fasthttp for zero-allocation request handling. The sync.Pool-backed DefaultCtx, UnsafeString/UnsafeBytes conversions, and the 3-char prefix routing tree all serve this goal. The tradeoff is that net/http compatibility requires the middleware/adaptor bridge package.

  2. Generated Ctx interface via ifacemaker. Rather than hand-writing the 100+ method Ctx interface, Fiber generates it from DefaultCtx annotations. This keeps interface and implementation in sync automatically and enables mock implementations for testing without manual upkeep. It is an unconventional choice that pragmatically solves a real maintenance problem.

  3. Monorepo middleware distribution. All 30+ middleware packages live in the same module, versioned together. This eliminates “middleware version mismatch” bugs at the cost of a larger repo. Middleware can rely on unexported types in internal/ and get first-class CI coverage.

  4. Dual dispatch path: DefaultCtx vs CustomCtx. The router has two code paths — a fast path for the common case (*DefaultCtx type assertion in requestHandler) and a general path for user-defined context types (nextCustom). This avoids interface overhead on the hot path while still supporting extensibility.

  5. Service interface for managed lifecycle. Rather than requiring users to wire shutdown hooks manually, the Services []Service config field provides a structured start/stop lifecycle with state tracking. This bridges the gap between “framework” and “application server” use cases without imposing a full DI framework.