3 reasons to use Fiber over Gin for your next Go web project
TLDR
- A superior router for RESTful routes.
- Built on top of the high performance fasthttp.
- Extremely responsive dev team.
I recently switched from using Gin to Fiber for building my site generator. Fiber was the third web framework I moved to, starting first with Iris, then moving to Gin, before finally using Fiber.
After moving from Iris to tried and true Gin, switching frameworks again was the last thing I wanted to do, but when my routes became sufficiently complex, I had no choice.
Iris
But first, why wasn’t I happy with Iris? The tool looks great, and so do the docs—at first glance, but in the end, I experienced a dizzying array of documentation in different location for different versions (v12 was the latest at the time, not merged to master) which didn’t always work as shown. I generally have a high tolerance for out of date documentation because I understand how difficult it is to keep the docs in sync with the code, so I tend to just read the source instead, but the source what finally made me switch.
The Iris source code is not easy to read, at least on Github. The project is broken down into many files over many packages, and I often found myself reading the wrong version of a file because I was viewing the master branch. Compared to Gin which I knew, and Fiber, where the bulk of the code is in a single Go file, Iris simply wasn’t worth the effort of digging through documentation for my simple project. Maybe my experience would have been different if I bought the book, but I'm not ready for that type of open source gatekeeping
Gin
Gin is a great piece of software. It's been around forever and uses the standard Handler interface from net/http which makes it comfortable to use and easy to add to any project. The code is clean, easy to navigate, and easy to understand. Switching from Iris to Gin was actually fairly simple because they both offer a lot of the same primitives, and both use the same type of handler functions. It wasn't until my routing began to resemble a standard REST API that I ran into issues with the router. I searched the issue list on Github and found a handful of people reporting the same problem I faced. Maybe a few handfuls. One issue sums it up succinctly…
To everyone who's new here:
If you use RESTful-Style API, router of gin will be a TROUBLEMAKER!
The root of the problem is httprouter
I read multiple comments like the one above, akin to “implementing REST? You need a different router.” I wanted RESTful routes but I also needed nontrivial wildcard routes. I thought about using go:generate to create the dynamic routes I knew I needed beforehand, but after hacking a few makeshift, I decided to look for another framework.
The real problem: Gin's router panics on ordinary REST routes
It's worth spelling out exactly why the router is a troublemaker, because the conflict is baked into the design. Gin sits on top of httprouter, a radix tree that matches routes by prefix. That gives it great performance, but the prefix model means a literal segment and a wildcard in the same position can't coexist. So these two completely reasonable REST routes don't just behave oddly — they panic at startup:
1 2 3 | |
A collection route and a named sub-route under the same resource is one of the most ordinary things a REST API does, and yet Gin refuses to register both. The reports of "wildcard route ':different' conflicts with existing children" and "root level wildcard parameters" have piled up for years. The suggested workarounds are grim: people register only /users/:id and then switch on the param value inside the handler, routing "info" by hand:
1 2 3 4 5 6 7 8 | |
That's not routing anymore, that's a manual if/else tree. It's the kind of duct tape I'd hoped a framework would spare me from, and it only gets worse the more your routes overlap. The frustrating part is that every alternative solves this gracefully — see the last section of this post.
Fiber
I found a link to Fiber and decided to give it a try. I was skeptical at first because it’s influenced by a piece of node software, and I’m generally leery of all things node, but I decided to try it. I immediately tested my routing issue, and was happy when Fiber handled the problem in a perfectly sane way.
3) Responsive dev team
I did have one problem however. My wildcard route was returning inconsistent results! Just when everything was looking so promising. I submitted a bug report which was acknowledged within 4 hours, and had a PR the next day!
I began porting my code from Gin to Fiber and was thrilled to find that Fiber had a parallel for everything I did in Gin. At times, I found myself deep in the fasthttp codebase, which Fiber effectively wraps, and that took some getting used to, but when I’m there I’m happy to be there because I know I’m that much closer to the metal.
Fiber’s source is very predictible to read. Most everything you care about is in ctx.go or app.go, and it ships with some very useful middleware like favicon, etag, pprof, filesystem, and more. So far, Fiber is my favorite Go web server, and I hope it works for you too!
An update — these days, I've changed my mind
I want to be honest about something, because this post still gets traffic and I don't want to leave anyone with the wrong impression. When I wrote the original version of this article, I genuinely loved Fiber — and a big part of that was the raw performance it promised through fasthttp. Being "closer to the metal" felt great, and I said so above.
Since then, I've mellowed a lot. Almost everything I build now is a hobby site or a small internal tool. Those services don't serve thousands of requests a second. They don't have a scaling problem, and they never will. The performance hacks that made Fiber appealing are real, but they buy me nothing that a humble hobby site will ever notice. And they come with a real cost: fasthttp doesn't speak the standard http.Handler interface, so Fiber's ecosystem doesn't interoperate with the entire world of net/http middleware the way stdlib-based routers do.
So if I were starting one of these projects today, I would not reach for Fiber. For the vast majority of my work the best answer is a lot simpler:
- The standard library. Since Go 1.22,
net/http's built-inServeMuxdoes method matching and{wildcard}path parameters natively — no third-party dependency at all. And it handles the exact case that tripped up Gin's router: overlapping patterns like/posts/{id}and/posts/latestare both allowed, with a "most specific pattern wins" precedence rule instead of a startup panic. - Or chi. If I outgrow the stdlib's modest feature set, chi is my default. It's built on a radix trie like Gin's router, but it doesn't panic on those overlaps, it supports regex parameters like
/articles/{slug:[a-z-]+}, its middlewares are plainhttp.Handlers (100% stdlib-compatible), and the core router is under 1000 lines with zero external dependencies.
The point of this article was never really fiber-versus-gin in the abstract. It was about Gin's router being the weak link in an otherwise fine framework — the one thing that finally pushed me to switch. That conclusion still stands, and if anything it's stronger today, because now ordinary, boring tools handle the same routes with less fuss than Gin does. Stdlib with or without chi is, in my experience, the best place to be.