Back tostdlib
Blog Post

Serverless Exit: A Technical Leader's Guide to Transitioning Away from Serverless

Unkey rebuilt API from serverless to Go servers and slashed latency 6x. Serverless caching required network requests that added 30ms+ at p99.

Unkey rebuilt entire API stack from Cloudflare Workers to Go servers, slashed latency 6x. Serverless seemed perfect initially: global edge deployment, automatic scaling, pay-per-use pricing. But when you're in critical path of API authentication, every millisecond matters. After two years fighting serverless limitations, they completely changed approach and got dramatically simplified architecture that enabled self-hosting and platform independence.

Fundamental issue was caching. In serverless you have no guaranteed persistent memory between function invocations. Every cache read requires network request to external store. Used global scope trick to cache data across invocations but hit rates were very low. Cloudflare's cache had good hit rate but latency not acceptable, consistently took 30ms+ at p99 for cache reads. When trying to build sub-10ms API that's showstopper. Zero network requests always faster than one network request. No amount of stacking external caches could get around this fundamental limitation.

SaaS glue problem: serverless promised you wouldn't need to worry about operations. Cloudflare Workers themselves were stable, but you end up needing multiple other products to solve artificial problems that serverless itself created. Need caching? Add Redis. Need batching? Add Queue and downstream handler. Need real-time features? Add Something. Each service adds latency, complexity, another point of failure plus charges. These aren't inherent technical challenges but limitations imposed by serverless model. In traditional server you'd have all these capabilities built-in or easily accessible without network hops. Ended up using Cloudflare Durable Objects, Logstreams, Queues, Workflows plus homemade stateful servers on top. Constantly evaluating and integrating new SaaS products not to add business value but just to work around constraints of chosen architecture.

Data pipeline nightmare: API emits events for every key verification, rate limit, API call. In traditional servers you'd batch these in memory and flush periodically. In serverless you have to flush on every single function invocation because function might disappear after handling request. Built elaborate overly complex pipeline. For analytics events built chproxy specifically because ClickHouse doesn't like thousands of tiny inserts. For metrics and logs couldn't send directly to Axiom due to rate limits, had to build buffering service. Essentially built distributed event processing system with multiple failure points just to work around serverless limitations.

Solution with stateful Go servers: instead of complex pipeline just batch events in memory and flush directly every few seconds or whenever buffer reaches certain size. No auxiliary services, no complex log pipelines, no coordination. Just straightforward batching any server application would do. Strategic benefits beyond performance: self-hosting becomes trivial (docker run command), improved developer experience (no working around function limits, data persistence issues, debugging across distributed logs), platform independence (can deploy anywhere, use any database, integrate with any third-party service).

Serverless makes sense for infrequent workloads (scaling-to-zero economics unbeatable), simple request/response patterns (don't need persistent state or complex data pipelines), event-driven architectures (excels at responding to events without managing infrastructure). Serverless struggles when you need consistent low latency (external networked dependencies kill performance), require persistent state (working around statelessness creates complexity), have high-frequency workloads (per-invocation model becomes expensive), need fine-grained control (platform abstractions become limitations). Biggest lesson: understanding complexity tax of working around platform limitations. Sometimes best solution isn't to work around limitations but to choose different foundation.

Source: unkey.com
#serverless#cloud architecture#technical leadership#engineering management#migration#cost optimization

Problems this helps solve:

Decision-makingProcess inefficiencies

Explore more resources

Check out the full stdlib collection for more frameworks, templates, and guides to accelerate your technical leadership journey.