mrkeyoor.com_
Fri 16 Oct 18:51 UTC
Tech6 min read

Lambda Web Functions Cut CPU Wait Charges, but Memory Keeps Billing

AWS now runs ordinary Node.js HTTP servers on Lambda. Active CPU billing changes the cost of waiting, while memory, concurrency and network limits still shape the bill.

An API can spend most of a request waiting on a database while its memory bill keeps running. AWS's new Lambda Web Functions separate those costs: CPU is metered for active work, and memory accrues throughout an execution environment's life, including gaps between requests. That distinction in the developer documentation matters if you're considering moving an existing web server to the service. A slow downstream call may consume little CPU, but keeping the server available still has a price.

AWS announced Web Functions on October 12, adding a port-listening HTTP programming model alongside its event functions and MicroVMs. The launch supports Node.js 24 on Arm64 in five regions: Northern Virginia, Ohio, Oregon, Tokyo and Ireland. Developers can deploy a conventional web server without converting its routes into Lambda event handlers. The practical question is how that server behaves, and what it costs, once requests share a process.

The bill follows the server as well as the request

AWS's pricing examples make the distinction concrete. Its hypothetical API handles 10 million requests a month, each taking 200 milliseconds from start to finish but using 50 milliseconds of active CPU. With roughly 300MB of consumed memory, AWS calculates $13.85 for CPU, $2.76 for memory and $3 for requests, totaling $19.61.

Those figures assume Arm compute in Northern Virginia, evenly spread traffic and exactly one execution environment running throughout a 30-day month. They exclude data transfer and the free tier. They're an illustration of the charging model, rather than a measured customer bill or a comparison against the same application on another service.

The pricing page meters compute at one-millisecond granularity and shares an environment's compute and memory across concurrent requests. For your own estimate, the missing input is how many environments actually stay alive under your traffic pattern. A server that waits often can save CPU charges, while extra environments still add memory charges. Counting requests and their average duration alone won't reproduce the example.

Concurrency changes how waiting is used

A warm server can handle another request while the first awaits a database response. AWS's scaling documentation sets a default upper bound of 64 simultaneous requests per environment, configurable from one to 128. Lambda adjusts the actual concurrency limit dynamically according to resource use, so choosing 128 doesn't promise that every environment will serve that many requests at once.

The endpoint also has separate controls for the number of environments and incoming requests per second. These limits operate per region. Raising a request-rate limit won't help if all permitted environments are already occupied. AWS returns HTTP 429 when capacity or rate limits prevent it from accepting more traffic.

For a streaming API, this separates two things developers need to measure: how much work a request performs and how long it occupies a connection. Waiting can be cheap in CPU terms while still using concurrency capacity. The scaling guide also says there is no minimum or reserved-environment setting. You can't configure a permanent warm floor through those controls.

Existing Node.js code still needs a startup check

The runtime guide describes a managed Node.js 24 runtime that loads index.js from the package root by default. Your server must read AWS_LAMBDA_HTTP_ENDPOINT and listen on its supplied host and port. Next.js standalone deployments, which use their own listening variables, need an entry file that sets those values before starting the server.

Each execution environment has 2GB of memory, with a default V8 heap of 1,024MB. Heap space, buffers and native allocations must fit alongside the runtime and concurrent requests. That makes the memory footprint under load a more useful migration check than the size of one response.

AWS patches the runtime automatically. Web Functions don't support pinning a particular patch version or disabling those updates. The application keeps its declared major runtime, but teams that depend on a specific Node.js patch need to account for this managed update policy.

A warm process isn't permanent storage

The execution lifecycle documentation requires the server to begin listening within 10 seconds. When traffic has fallen to zero, the next request triggers a new environment and waits through initialization. Sharing warm environments can reduce the need for new ones during small traffic increases, but it doesn't remove that first-request delay.

Reused environments retain global variables, connections and local files between requests. They have no guaranteed lifetime. AWS tells developers to persist important data outside the process, and warns against keeping request-specific state in global variables. Concurrent requests can interleave across an await, making shared mutable state a correctness issue even on Node.js's main thread.

Shutdown is brief. Lambda stops sending new requests, lets requests already running finish on a best-effort basis, then sends SIGTERM. The process gets up to one second for cleanup, and AWS doesn't guarantee graceful shutdown in every failure mode. A cache or connection pool can benefit from reuse. A write that must survive termination needs an external destination.

Global routing has a private-network boundary

The networking guide contains a restriction that matters for database-backed applications: VPC egress connectors work only with HomeRegion endpoints. Lambda rejects a MultiRegion or PerRegion endpoint routed to a revision that references one of those connectors.

Without a connector, a revision can reach public IPv4 destinations, but it has no route to resources with private addresses in your VPC. With a connector, outbound traffic follows your VPC's routing and security rules. The connector doesn't make the inbound endpoint private, and it doesn't supply internet access by itself.

That means an application using a private database cannot combine its connector-backed revision with the service's global endpoint in the way a simple public-API demo can. The design decision precedes deployment: determine where the application must connect before choosing its endpoint type.

AWS also documents half-duplex request handling and no WebSocket upgrades. Responses can stream, including server-sent events, but the request body must finish arriving before the response is delivered. Check that contract against the application's actual connection behavior.

HTTPS doesn't supply application authentication

According to the endpoint access-control guide, the deploy command creates an ApplicationManaged endpoint by default. Lambda passes requests through, leaving authentication and authorization to your code. A TLS-protected URL therefore doesn't imply restricted access.

The alternative, IamAuth, requires signed requests and permission to invoke the endpoint. CloudFront can sign origin requests on a viewer's behalf. For that arrangement, AWS documents a resource policy scoped to the intended distribution. An application-managed endpoint remains directly reachable at its Lambda domain even when CloudFront fronts it, so placing a distribution in front doesn't itself prevent bypass.

A successful deployment still needs a real request

The launch walkthrough uses this command to bundle an application and create its endpoint:

aws lambda-web deploy --name my-web-app --code ./my-app

The resource model separates immutable revisions from endpoints that route traffic to one or two revisions. That permits a gradual rollout and a rollback by changing traffic weights. An endpoint can remain active while an update is in progress, and a failed update across regions can leave some regions using the previous configuration.

AWS explicitly warns that an active revision, active endpoint or successful endpoint update doesn't confirm that the HTTP server starts. After deployment, send a request and inspect the logs. This is a useful limit on what the deployment command has proved: resource creation has succeeded, while the application still needs to answer.

The same guide gives requests a default timeout of 30 seconds, configurable up to 900 seconds. Long streams need that setting checked before a test can establish that they finish successfully.

The next evidence to watch is production measurement across different traffic patterns. AWS's product page includes customer performance claims, including roughly 30% improvement reported by Breadcrumb.ai, but those testimonials don't establish your application's result. A useful comparison would record memory consumption and environment counts alongside latency, especially the first request after an idle period. That's how to find out whether cheaper waiting produces a lower total bill.

We reviewed this

  1. requests — our honest review
  2. runtime — our honest review
  3. distribution — our honest review

Sources

  1. AWS Lambda Web Functions developer guide
  2. Announcing AWS Lambda Web Functions
  3. AWS Lambda pricing
  4. Scaling behavior for Lambda Web Functions
  5. Lambda Web Function runtimes
  6. Execution environment lifecycle
  7. Configuring networking for AWS Lambda Web Functions
  8. Lambda Web Function endpoint access control