This episode covers file upload in Fiber v3: the multipart middleware with Memory configuration, reading files via c.FormFile and c.SaveFile, uploading many files and extra fields, body size limits, and re-serving uploaded files.

Almost every web application needs to accept files: avatars, attachments, documents. Episode 17 covers file upload in Fiber v3 — how to process multipart forms, read and save files, set size limits, and re-serve uploaded files.
File upload looks simple, but has many pitfalls: file size, memory, filename security, and body limits. Understanding Fiber's multipart mechanics solves those problems from the start.
Fiber v3 provides the multipart middleware to control how much form data is held in memory before being written to disk:
import "github.com/gofiber/fiber/v3/middleware/multipart"
app.Post("/upload", multipart.New(multipart.Config{
Memory: 10 << 20, // 10 MB
}), func(c fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
return c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
})Memory: 10 << 20 means files up to 10 MB are held in memory; above that they're written to a temporary file on disk. c.FormFile("file") retrieves the file by its form field name, and c.SaveFile saves it to the uploads folder.
c.FormFile returns a *multipart.FileHeader containing file metadata — Filename, Size, and Header:
app.Post("/upload", multipart.New(multipart.Config{
Memory: 10 << 20,
}), func(c fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
log.Printf("file: %s (%d bytes)", file.Filename, file.Size)
if file.Size > 5<<20 {
return fiber.NewError(fiber.StatusRequestEntityTooLarge,
"file terlalu besar")
}
return c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
})After FormFile, the metadata is available in FileHeader. Manual validation like checking Size can be done before saving. SaveFile opens, copies, and closes the file at the destination in one step.
Files rarely stand alone — they're often accompanied by other fields like a description. Combine FormFile and FormValue:
app.Post("/upload", multipart.New(multipart.Config{
Memory: 10 << 20,
}), func(c fiber.Ctx) error {
desc := c.FormValue("description")
file, err := c.FormFile("file")
if err != nil {
return err
}
if err := c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename)); err != nil {
return err
}
return c.JSON(fiber.Map{"description": desc, "saved": file.Filename})
})c.FormValue("description") reads a text field from the same form. This combination handles the real-world case: a file plus its metadata sent in one request.
To upload several files at once, iterate over fields with the same name:
app.Post("/upload", multipart.New(multipart.Config{
Memory: 10 << 20,
}), func(c fiber.Ctx) error {
form, err := c.MultipartForm()
if err != nil {
return err
}
files := form.File["photos"]
for _, f := range files {
if err := c.SaveFile(f, fmt.Sprintf("./uploads/%s", f.Filename)); err != nil {
return err
}
}
return c.JSON(fiber.Map{"count": len(files)})
})c.MultipartForm() returns the complete form structure; form.File["photos"] contains all files with the field name photos. The loop saves each one. For very large uploads, consider a queue — saving hundreds of files in one request can cause timeouts.
The upload request size is limited by BodyLimit — 4 MB by default. Adjust it if your application accepts large files:
app := fiber.New(fiber.Config{
BodyLimit: 20 * 1024 * 1024, // 20 MB
})BodyLimit: 20 * 1024 * 1024 raises the total request body size limit to 20 MB. If a request exceeds the limit, Fiber returns status 413. Set the multipart middleware Memory lower than BodyLimit so medium-sized files are written to disk instead of burdening RAM.
curl -X POST -F "description=avatar lama" -F "file=@./avatar.png" \
http://localhost:3000/upload
curl -X POST -F "photos=@a.png" -F "photos=@b.png" http://localhost:3000/uploadThe first request sends one file plus the description field; the second sends two files with the photos field. Check the ./uploads folder — files are stored under their original names, and the logs show each file's size.
Key takeaways:
multipart middleware with Memory config controls file retention in memory vs disk.c.FormFile("file") retrieves a file; c.SaveFile saves it to a destination.FileHeader provides Filename, Size, and Header for validation.c.FormValue reads text fields from the same form.c.MultipartForm().File[name] handles multi-file uploads.fiber.Config{BodyLimit} limits the request size (default 4 MB).In the next episode, episode 18, we discuss CSRF, CORS, and security — the csrf and cors middleware in Fiber, origin configuration, and practices for protecting APIs from cross-site attacks.