AWS recently announced AWS Lambda Web Functions, a new kind of Lambda function that runs your code as a Node.js HTTP server listening on a port, rather than as a handler receiving an event. To tell the two apart, the Lambda functions you already know are now called Event Functions. AWS says Web Functions suit web applications, API backends and other HTTP workloads with many concurrent requests.
Until now, the usual ways to run an API on Lambda have been these:
- One function per route behind API Gateway.
- The whole app in one function behind an adapter, the Lambdalith.
- A function URL in front of one function, with no API Gateway at all.
The adapters made that work by turning every event back into a request your framework understands, but you were left with one request at a time per environment, billing for the time spent waiting on I/O and a 6 MB payload limit, which is why Aidan Steele, AWS Hero, calls the approach "always a hack". Even AWS's own Lambda Web Adapter now recommends Web Functions for new Node.js web apps.
The one Web Functions-specific detail is the address your server listens on, which Lambda passes as a host and port in the AWS_LAMBDA_HTTP_ENDPOINT environment variable, as in the Express example from the announcement:
import express from 'express';
const app = express();
const [host, port] = process.env.AWS_LAMBDA_HTTP_ENDPOINT.split(':');
app.get('/', (req, res) => {
res.json({ message: 'Hello from Lambda Web Functions!' });
});
app.listen(port, host, () => {
console.log(`Server running on port ${port}`);
});
Because a Web Function is a plain Node.js server, local development and testing are simpler than with an Event Function behind API Gateway, where local testing can take an emulator such as sam local start-api, running your functions in a local Docker container. On your laptop nothing sets the variable, so you set it yourself and run the same index.js with Node:
AWS_LAMBDA_HTTP_ENDPOINT=127.0.0.1:3000 node index.js
What changes in practice is that one environment handles up to 128 requests at once, 64 by default, so a burst of traffic shares warm environments instead of starting one per request. Lambda bills compute for the CPU time your code actually uses, so a request waiting on a database or another API uses little of the CPU you pay for.
One caveat: anything your code keeps in a module-level variable is shared by every request in that environment, so a value meant for one request can end up in another. The docs are clear that your code must be safe for concurrent use.
Web Functions make me wonder whether it's time to rethink the Lambdalith, which we've long treated as a pattern to avoid. AWS's own Lambda guide lists it among anti-patterns that "work but can increase costs and complexity", and Yan Cui, AWS Serverless Hero, covered its trade-offs and adopted it "where it makes sense". On his podcast, in a conversation recorded before Web Functions existed, he weighed a tailored IAM role on each function and lighter cold starts against how useful one function was for bringing an existing Express app across. His guest, Heitor Lessa, who created Powertools for AWS Lambda while at AWS, said he usually started from one function and split it as the boundaries and the permissions became clear.
Web Functions soften the cold-start side of the case for splitting, since environments start less often, but not the permissions side, because every route runs under the same execution role. Still, a Node.js server we'd have put in a container on Fargate could now run as a single Web Function, which makes the Lambdalith look less like an anti-pattern and more like a choice with its own trade-offs.
An API Gateway REST API checks API keys, holds each customer to a usage plan and throttles a noisy neighbour without slowing everyone else. A Web Function comes with its own HTTPS endpoint, which does none of that, and its rate limit applies to the whole endpoint in each Region. That leaves the question of whether you still need API Gateway.
What goes in front
If you need a custom domain, AWS WAF or caching, AWS recommends putting CloudFront or API Gateway in front of the endpoint, since the endpoint itself doesn't support custom domain names or direct AWS WAF association. The endpoint's domain stays reachable from the internet, so clients can go around whatever you put in front unless the endpoint refuses them:
Nothing in front
Each endpoint has an authentication type, a setting that controls which requests reach your code. The default, ApplicationManaged, lets every request through to your code, while IamAuth accepts only requests signed with SigV4 by an IAM identity allowed to invoke the endpoint. An IamAuth endpoint suits calls between services inside AWS, where every client already has an IAM identity, as long as they can share the endpoint's rate limit. Lambda doesn't add CORS headers for Web Functions, so your app answers preflight requests itself.
CloudFront
CloudFront is another option that lets you make the endpoint refuse requests that don't come through your distribution, using origin access control on an IamAuth endpoint. CloudFront signs every request it sends, though requests signed by any IAM identity your policies allow still get through. To let CloudFront in, you attach this resource-based policy from AWS's CloudFront guide, with aws lambda-web put-resource-policy on the function's ARN, not the endpoint's:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontOACAccess",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "lambda:InvokeWebFunctionEndpoint",
"Resource": "arn:aws:lambda:us-east-1:111122223333:web-function/my-function/endpoint/prod",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}
Your app can still check its own tokens, such as a JWT, because CloudFront adds its signature in a dedicated header and passes the viewer's Authorization header to the origin unmodified, as long as the header is in the cache policy. That also puts the header in the cache key, so with caching on, CloudFront keeps a separate copy of each response per token.
AWS WAF on the distribution can limit how often each client calls, by IP address or by a header value over a window of one to ten minutes, though AWS says it's not intended for precise request-rate limiting. A request that leaves the header out isn't evaluated or rate limited.
You give up Lambda@Edge origin request and origin response triggers on any cache behaviour that reaches the endpoint through origin access control. CloudFront's signature doesn't cover the body of PUT, POST and PATCH requests either, which the HTTPS connection to the endpoint protects in transit.
API Gateway
API Gateway reaches the endpoint through a plain HTTP proxy integration, since there's no Web Functions integration. Both REST and HTTP APIs have authorisers, but API keys, usage plans with a quota per day, week or month, request validation and AWS WAF need a REST API. Usage plan throttling and quotas are applied on a best-effort basis, so clients can sometimes go over them.
Neither the Lambda nor the API Gateway docs describe a way for API Gateway to sign requests to an IamAuth endpoint, so the endpoint stays ApplicationManaged. Lambda's best practices tell you to verify a shared secret or token in your app instead, and API Gateway can add the secret as a header on every request through parameter mapping.
Before you move your API
- Node.js 24 is the only runtime.
- Web Functions run exclusively on Arm64 and deploy from a .zip file, not a container image.
- Each environment gets 2 vCPUs and 2 GB, which you can't change.
- Endpoints accept HTTP/1.1 requests only, with no WebSocket upgrades.
Running it has a few gotchas:
- Lambda doesn't check that your server listens when you deploy, so a revision can show
Activewhile every request fails. - Web Function metrics don't include a revision dimension, so during a canary you can't compare the two revisions in those metrics.
- Outbound requests come from an address that isn't stable, so a partner's allow list needs an egress network connector into your VPC and a NAT gateway.
- On top of CPU time, you pay for memory over the life of each execution environment, idle time between requests included.
If your API isn't on Express, Eric Johnson, Principal Developer Advocate at AWS, has recently written a pattern-driven tour of seven protocols and frameworks on Web Functions, including server-sent events, gRPC-Web and signed webhooks, with working, deployable code for every pattern.

Top comments (1)
The "Lambdalith is back on the menu" realization is the most interesting part of this announcement. But the fine print that you pay for memory over the lifetime of the environment, including idle time, fundamentally changes the economics. If your API gets trickle traffic 24/7, that environment stays warm, and you're paying that memory floor every second.
The IAM authentication note is also a huge architectural catch. Since API Gateway can't sign requests with SigV4 to an IamAuth endpoint, you're stuck leaving it as ApplicationManaged and manually verifying a shared secret in your app.
Do you think Web Functions will eventually get native API Gateway integration, or will AWS push everyone toward CloudFront + WAF for the "secure front door" use case?