Quick take
Build a custom gateway only if your routing logic is your product. Otherwise start with Kong or Envoy. Avoid managed cloud gateways unless you’re a small team that genuinely won’t outgrow them. I learned this the expensive way.
I’ve spent the better part of this year building Decloud’s API layer and working on gateway architecture at two enterprises. In that time I’ve touched every major approach: managed cloud gateways, Kong, Envoy, and a from-scratch Go gateway. Each one taught me something. Mostly what not to do next time.
This is the comparison I wish someone had handed me twelve months ago.
The Four Approaches
Let me lay out the options as I see them.
Managed cloud gateways – AWS API Gateway, Azure APIM, GCP Endpoints. You click buttons, write some config, and the cloud provider handles scaling, TLS, and basic auth. Sounds great until you need something slightly custom.
Kong – open-source, Lua plugin system on top of NGINX. Battle-tested. Huge plugin ecosystem. The enterprise version costs real money but the open-source tier is genuinely usable.
Envoy – C++ proxy out of Lyft. Incredible L7 features. The xDS API is elegant. Configuration is… not. YAML files that would make a Kubernetes manifest blush.
Custom Go gateway – you write net/http handlers, maybe use httputil.ReverseProxy, and own every line. Maximum control. Maximum responsibility.
The Comparison
Here’s what I’ve seen after running all four in some form of production:
| Managed Cloud | Kong | Envoy | Custom Go | |
|---|---|---|---|---|
| Time to first route | Minutes | Hours | Hours | Days |
| Plugin/extension model | Limited, vendor-locked | Lua plugins, large ecosystem | WASM/C++ filters | Write whatever you want |
| Operational burden | Low (it’s their problem) | Medium | Medium-High | High |
| Customization ceiling | Low | Medium-High | High | Unlimited |
| Latency overhead | Variable, opaque | Low (~1-2ms) | Very low (<1ms) | As low as you make it |
| Cost at scale | Expensive (per-request pricing) | Free OSS / expensive enterprise | Free | Engineering time |
| Observability | Vendor dashboards | Prometheus, logging plugins | Best-in-class (stats, tracing) | Roll your own |
| Learning curve | Low | Medium | Steep | Depends on your team |
When Each One Wins
Managed cloud gateway wins when you have fewer than 10 routes, a small team, and no unusual auth requirements. I used AWS API Gateway for a side project last year. Fine. Easy. The moment I needed custom header injection based on JWT claims it became a fight with VTL templates and I wanted to throw my laptop.
Kong wins for most teams. Seriously. If you’re a startup with 5-50 microservices and you need auth, rate limiting, request transformation, and logging – Kong does all of it with plugins you can install in minutes. We evaluated it for a the fintech startup project and it handled our OAuth2 flow, rate limiting per API key tier, and request/response logging without writing a single line of custom code.
The plugin system is the key. Need IP whitelisting? Plugin. Need correlation IDs? Plugin. Need to transform a response body? Plugin. You only hit the wall when you need plugin behavior that doesn’t exist yet and writing Lua makes you nervous.
Envoy wins when you’re deep into service mesh territory or need the absolute best L7 proxying available. The stats and tracing integration is genuinely best-in-class. If you’re already running Istio or have a platform team that lives and breathes infrastructure – Envoy is the right call.
But. The configuration complexity is real. I spent two days debugging an Envoy route that wasn’t matching because of a subtle regex difference between the documentation and actual behavior. Two days. For one route.
Custom Go gateway wins when your routing logic IS your business logic. At Decloud, we needed request routing that depended on tenant configuration, dynamic upstream selection based on resource availability, and custom protocol translation. No off-the-shelf gateway was going to do that without so many plugins and hacks that we’d have been maintaining a Frankenstein anyway.
So we built it in Go. net/http server, httputil.ReverseProxy for upstream forwarding, middleware chain for auth and rate limiting. About 3,000 lines of code for the core. It does exactly what we need and nothing else.
The Build vs Buy Decision
Here’s my actual framework. Three questions:
1. Is your routing logic generic or product-specific?
If generic (auth, rate limit, forward to upstream) – buy. Kong or Envoy. Don’t waste engineering weeks reimplementing what already exists.
If product-specific (tenant-aware routing, dynamic upstream selection, protocol translation) – build. You’ll end up maintaining custom code either way. Better to own the whole thing than fight a plugin system.
2. How big is your platform team?
Zero to two people? Managed cloud or Kong. You can’t afford to operate a custom gateway and also build your product. I’ve seen startups try. They end up with a half-broken custom proxy and a half-built product.
Three to five? Kong or Envoy. You have enough people to run infrastructure properly.
Ten plus? Build if you need to. You have the staffing to own it.
3. What’s your expected request volume in 12 months?
Under 10M requests/month – managed cloud is fine. The per-request pricing won’t kill you and the operational simplicity is worth it.
10M-1B – Kong or Envoy. You need control over performance and cost.
Over 1B – you probably already know the answer. Build or Envoy with a dedicated team.
Mistakes I’ve Made
Putting business logic in Kong plugins. We had a Lua plugin at the fintech startup that was doing user tier resolution and feature flagging. It worked until it didn’t. The plugin crashed under load because of a memory leak in our Lua code and took down the entire gateway. Business logic belongs in services. The gateway should validate and forward. That’s it.
Skipping circuit breakers in our custom gateway. First version of Decloud’s gateway had no circuit breaking. One upstream went slow, back-pressure built up, goroutines accumulated, memory spiked, gateway OOM’d. Classic. Added circuit breakers with gobreaker and a strict 2-second timeout on all upstreams. Should have been there from day one.
Ignoring the operational cost of custom. Writing a Go gateway is fun. Maintaining it at 3am when it’s dropping requests and you’re the only person who understands the routing table? Less fun. Factor in on-call burden when making the build decision.
What I’d Do Today
If I were starting fresh with a typical microservices platform:
- Start with Kong OSS. Get auth, rate limiting, and logging working in a week.
- Write custom plugins only when the existing ones genuinely don’t fit. Not when they “almost” don’t fit. Almost means they do fit and you’re being precious.
- Move to Envoy only if you’re adopting a service mesh and have the team to support it.
- Build custom only if your gateway IS your product differentiator.
The best gateway is the one your team can operate confidently at 3am. For most teams, that’s Kong. For some, it’s Envoy. For a few, it’s custom. For nobody, it’s the one you spent six months building because “we’re different.”
You’re probably not that different.