In October, AWS released Lambda web functions, a new kind of Lambda that runs your code as an ordinary Node HTTP server. We spent last week moving Webiny’s API onto them, and the short version is that the API got a lot faster. GraphQL requests answer 25 to 48% faster at the median, and when many requests arrive at once, they wait far less.
The change is in review now and will most likely ship in Webiny 6.6. This post is about what changes and the numbers we measured. How to switch a project you already have will come in a separate post, once it’s ready for you to try.
How the API runs today
Every request to a Webiny API on AWS takes the same path. CloudFront receives it, hands it to API Gateway, and API Gateway invokes the API’s Lambda function.
That setup has served us well for years, but it has two costs. API Gateway is one more hop on every request. It’s a good service if you need what it adds, like throttling, usage plans or request validation, but Webiny’s API used none of that. API Gateway only passed requests on to the Lambda. And a regular Lambda function handles one request at a time. When ten requests arrive at once and only three copies of the function are warm, Lambda starts seven new copies, and each of those requests waits for its copy to boot. For Webiny’s API that boot took about 1.1 seconds in our tests, before the request itself even started.
Here’s one request on that path, and the same request on a web function:

What a web function changes
A web function is a Node HTTP server that Lambda runs and scales for you. One running copy, which AWS calls an environment, serves many requests at the same time, the way any web server does. We let each environment take up to 16 at once.
CloudFront calls the web function directly, and there’s no API Gateway in between. /graphql, the Headless CMS APIs, the Website Builder routes and any custom routes you’ve added with <Api.Route> all go there. File requests lose API Gateway too. CloudFront now calls the file Lambda through its own Function URL, and the Lambda itself is unchanged.
Some things don’t change. Web functions only answer HTTP requests. So background tasks, scheduled publishing, the WebSocket API and the nightly trash cleanup still run on regular Lambda functions, exactly as before. They run the same code as the web function, so nothing behaves differently.
Why this needed 6.6
6.6 isn’t out yet. It’s still in the works, but without it we couldn’t have done this at all, because the backend didn’t have the architecture for it (that’s a topic for another post). Since the summer we’ve been building 6.6 in parallel with 6.5, and a big part of that work went into how the backend code is structured. That restructuring is what lets the same API code run on a web function, so for us the switch was mostly an infrastructure change and not a rewrite of the API. It’s also the work behind standalone Webiny, which runs the API as a plain Node process.
The numbers
We deployed the same project twice in eu-central-1, once with each setup. We called both through CloudFront, the way your users reach them, from the same machine in the same run. Each operation got 50 requests after 5 warm-up requests, alternating between the two setups.



