Skip to main content
Static middleware for Fiber serves static files from a specified directory or embedded filesystem. It provides features like directory browsing, file caching, compression, and byte range requests.

Signatures

func New(root string, config ...Config) fiber.Handler

Usage

import (
    "github.com/gofiber/fiber/v3"
    "github.com/gofiber/fiber/v3/middleware/static"
)

Basic Usage

// Serve files from ./public directory
app.Use("/", static.New("./public"))

// Or using app.Static shorthand
app.Static("/", "./public")

Custom Configuration

app.Use("/assets", static.New("./public", static.Config{
    Compress:  true,
    ByteRange: true,
    Browse:    false,
    MaxAge:    3600,
}))

Embedded Filesystem

import "embed"

//go:embed public/*
var embedFS embed.FS

app.Use("/", static.New("", static.Config{
    FS: embedFS,
}))

Multiple Static Directories

app.Static("/css", "./public/stylesheets")
app.Static("/js", "./public/scripts")
app.Static("/images", "./public/img")

Configuration

FS
fs.FS
default:"nil"
The file system to serve files from. You can use interfaces compatible with fs.FS like embed.FS, os.DirFS, etc. If not specified, uses the local filesystem.
Next
func(fiber.Ctx) bool
default:"nil"
Defines a function to skip this middleware when it returns true.
ModifyResponse
fiber.Handler
default:"nil"
Defines a function that allows you to alter the response before it’s sent.
NotFoundHandler
fiber.Handler
default:"nil"
Defines a function to handle requests when the file path is not found.
IndexNames
[]string
default:"[\"index.html\"]"
The names of the index files for serving a directory. When a directory is requested, these files are checked in order.
CacheDuration
time.Duration
default:"10 * time.Second"
Expiration duration for inactive file handlers. Use a negative value to disable caching.
MaxAge
int
default:"0"
The value for the Cache-Control HTTP header that is set on the file response. MaxAge is defined in seconds.
Compress
bool
default:"false"
When set to true, the server tries minimizing CPU usage by caching compressed files. This works differently than the compression middleware.
ByteRange
bool
default:"false"
When set to true, enables byte range requests for partial content delivery (useful for video streaming).
Browse
bool
default:"false"
When set to true, enables directory browsing and generates directory listings.
Download
bool
default:"false"
When set to true, enables direct download by setting the Content-Disposition header to attachment.

Default Config

var ConfigDefault = Config{
    IndexNames:    []string{"index.html"},
    CacheDuration: 10 * time.Second,
}

Common Use Cases

Serve SPA (Single Page Application)

app.Static("/", "./dist")

// Fallback to index.html for SPA routing
app.Use(func(c fiber.Ctx) error {
    return c.SendFile("./dist/index.html")
})

Serve with Browser Caching

app.Use("/static", static.New("./public", static.Config{
    MaxAge: 86400, // 1 day in seconds
}))

Enable Compression

app.Use("/assets", static.New("./public", static.Config{
    Compress: true,
    MaxAge:   86400,
}))

Video Streaming

app.Use("/videos", static.New("./media", static.Config{
    ByteRange: true,
    MaxAge:    3600,
}))

Directory Browsing

app.Use("/files", static.New("./documents", static.Config{
    Browse: true,
}))

File Downloads

app.Use("/downloads", static.New("./files", static.Config{
    Download: true,
}))

Embedded Static Files

import "embed"

//go:embed dist/*
var distFS embed.FS

app.Use("/", static.New("", static.Config{
    FS: distFS,
}))

Custom 404 Handler

app.Use("/assets", static.New("./public", static.Config{
    NotFoundHandler: func(c fiber.Ctx) error {
        return c.Status(404).SendString("Asset not found")
    },
}))

Modify Response Headers

app.Use("/files", static.New("./public", static.Config{
    ModifyResponse: func(c fiber.Ctx) error {
        c.Set("X-Served-By", "Fiber Static")
        return c.Next()
    },
}))

Multiple Index Files

app.Use("/", static.New("./public", static.Config{
    IndexNames: []string{"index.html", "index.htm", "default.html"},
}))

Best Practices

Use Path Prefix for Organization

// Good - organized under /static
app.Static("/static", "./public")

// Avoid - serves from root
app.Static("/", "./public")

Enable Caching in Production

if os.Getenv("ENV") == "production" {
    app.Static("/assets", "./public", static.Config{
        Compress: true,
        MaxAge:   86400 * 7, // 1 week
    })
} else {
    app.Static("/assets", "./public")
}

Secure Directory Browsing

// Only enable in development
app.Use("/files", static.New("./uploads", static.Config{
    Browse: os.Getenv("ENV") == "development",
}))

Handle Static Files Before Routes

// Middleware
app.Use(logger.New())

// Static files
app.Static("/public", "./public")

// Routes
app.Get("/api/users", getUsers)

Use Embedded FS in Production

import "embed"

//go:embed dist
var dist embed.FS

if os.Getenv("ENV") == "production" {
    app.Use("/", static.New("", static.Config{
        FS:     dist,
        MaxAge: 86400,
    }))
} else {
    app.Static("/", "./dist")
}

Disable Caching for Development

app.Use("/assets", static.New("./public", static.Config{
    CacheDuration: -1, // Disable file caching
}))

Performance Tips

Enable Compression for Text Files

// Compress text-based assets (CSS, JS, HTML)
app.Use("/assets", static.New("./public", static.Config{
    Compress: true,
}))

Set Appropriate Cache Duration

// Short cache for frequently changing files
app.Static("/", "./dist", static.Config{
    CacheDuration: 5 * time.Second,
})

// Long cache for versioned assets
app.Static("/static", "./public", static.Config{
    CacheDuration: 1 * time.Hour,
    MaxAge:        86400 * 365, // 1 year
})

Use Byte Range for Large Files

// Enable for video, audio, and large downloads
app.Static("/media", "./media", static.Config{
    ByteRange: true,
})

Notes

  • Files are cached in memory based on CacheDuration to improve performance
  • The Compress option caches compressed versions of files, not on-the-fly compression
  • When using embedded filesystems, the binary includes all files at compile time
  • Directory browsing can be a security risk - only enable when necessary
  • MaxAge: 0 means no browser caching; files are re-validated on each request
  • Byte range requests are essential for video streaming and large file downloads

Build docs developers (and LLMs) love