When AWS announced Lambda Web Functions in October, I was excited.
At Easel, we'd spent months building infrastructure to run web applications efficiently on traditional Lambda. Native HTTP servers, concurrent requests, and active CPU billing sounded like exactly what we'd been looking for.
If Web Functions worked the way we hoped, we could potentially replace a substantial amount of our custom infrastructure.
So we decided to put them to the test.
A few weeks later, we'd decided to run our own compute instead. And as it turns out, our own infrastructure was faster, too.
Our initial experiments were promising. Web Functions handled 300 concurrent requests without errors, and a new function was serving requests in under nine seconds.
But we quickly ran into something that didn't work for us.
AWS documents that Web Functions bill for memory throughout an execution environment's lifetime, even when no requests are running. What the documentation doesn't specify is how long an idle environment will remain alive before being terminated.
In our tests, environments continued running and accruing memory charges for 5–7 minutes after their last request.
Across six representative environments, we measured idle periods of 313–411 seconds. There was no configurable idle timeout to shorten them.
5–7 minof memory billed after the last request
Last requestIdle, memory billedLower is better
For a 200ms request followed by 345 seconds of inactivity, that's roughly 1,700 times the request duration in metered memory time.
We checked the economics against CloudWatch and AWS Cost Explorer. Across our experiment, memory accounted for approximately 88% of the calculated compute and request costs at published list prices, even though our application only used around 160–210 MB.
The entire experiment amounted to about two cents at list prices. Hardly alarming on its own.
For an application receiving steady traffic, this may not matter much. The same environment can serve many requests, spreading the idle-memory cost across them.
But Easel needs to support thousands of applications with unpredictable traffic, including many that receive only a handful of requests per day. For those workloads, an environment might spend five minutes waiting for traffic after serving a request that took only a few milliseconds.
Multiply that across thousands of independent deployments, and the economics start to look very different.
We even tried terminating environments ourselves after 10 seconds of inactivity. That reduced metered environment time by roughly 20×, but AWS recorded every intentional exit as a runtime failure.
It wasn't something we wanted to rely on in production.
Rather than adopt Web Functions, we decided to move application execution onto servers we operate ourselves, keeping traditional Lambda available for overflow.
This gives us control over scheduling and resource allocation. We can share capacity across applications without paying AWS for each idle environment, and scale beyond our own infrastructure when demand requires it.
Easel.sh edge
ServingIdle
Our first self-operated compute host went live in US East on November 2, serving applications including Easel's own website.
But taking ownership of the compute raised another question: How would our performance compare to AWS?
We deployed the same Next.js 16 application to both platforms and ran a series of benchmarks from a client in Ashburn, Virginia.
The results surprised us.
1.5–3×faster warm requests on the same Next.js app
Easel.shAWS Lambda Web FunctionsMedian ms · lower is better
Server-side rendering2.1×
Streaming (first chunk)2.0×
Our host delivered 1.5–3× faster median warm-request times across all four workloads.
The difference wasn't limited to network or routing overhead. Running the same 20,000 chained SHA-256 operations took 29.2ms on our host versus 43.8ms on Web Functions, about 1.5× faster.
And cold starts told a similar story.
After leaving both applications idle for 12 minutes, we triggered fresh execution environments on each platform.
3.5×faster cold starts after 12 minutes idle
Fastest to slowest of two trialsLower is better
Easel.sh: 216–250 ms
AWS Lambda Web Functions: 810–854 ms
In both trials, Easel started serving requests about 3.5× faster.
We also saw an interesting difference after a shorter idle period. Following one five-minute gap, Web Functions had already terminated its environment and needed 908ms to respond. Easel resumed its paused environment and responded in just 14ms.
These are early results from a single region and a small application, not a comprehensive performance study. The cold-start comparison has only two paired samples, and we haven't benchmarked sustained throughput yet.
Still, seeing our own infrastructure outperform AWS across these initial workloads was encouraging.
Running our own compute comes with additional responsibilities. We have to manage capacity, handle failures, and make sure resources are distributed efficiently across applications.
But it also gives us the freedom to optimize the entire execution path, rather than working around the constraints of another platform.
Web Functions may be a good fit for applications with sustained traffic, where idle memory costs are less significant. For Easel, the economics of running large numbers of independent applications led us in a different direction.
And our initial benchmarks suggest that the decision doesn't have to come at the expense of performance.
We're taking on more infrastructure complexity so developers using Easel don't have to.