AWS Lambda Is a Family Now: What Changed Since 2025 and What You Actually Need

Event Functions, Web Functions, MicroVMs, Durable Functions, Managed Instances: AWS Lambda changed more in 15 months than in the five years before. What each one is for, and when to ignore it.

Thimo Koenig Oct 17, 2026

The AWS Lambda function you’ve been writing for years got a new name last week: it’s an “Event Function” now. Your code and configuration don’t change, and the API and CloudFormation still say Function, but the rename tells you where AWS is going. Lambda isn’t one product anymore. It’s a family of three compute models, and they play by very different rules.

We recently built a fully serverless platform that keeps data on more than 650 trade fairs up to date using two AI agents. Lambda stages with SQS (Simple Queue Service) in between, job tracking in DynamoDB, hand-rolled retry and backoff logic, a fallback agent packaged as a container image. We read every Lambda announcement of the last 15 months with one question in mind: what would we build differently today? And which of it is nice engineering that doesn’t help us at all?

The short version

Event Functions Web Functions MicroVMs
Invoked by Events: SQS, S3, EventBridge, API Gateway … HTTPS endpoint Dedicated HTTPS endpoint per VM
Programming model Handler receives a JSON event Your code listens on a port Any process, built from a Dockerfile
Requests per environment One (except on Managed Instances) Up to 128 concurrent (default 64) One VM per user or session
Max duration 15 minutes per invocation; up to a year in total with Durable Functions 15 minutes per request 8 hours, with suspend/resume
Billing Wall-clock time × configured memory Active CPU time + memory actually used vCPU- and GB-seconds, no compute charge while suspended
Good for Backend processing, pipelines User-facing APIs, server-side rendering (SSR) Running untrusted or AI-generated code

Two more features cut across Event Functions only. Managed Instances change where your function runs. Durable Functions change how long it runs and how it remembers state.

Event Functions: Classic Lambda gets new options

Durable Functions: The one we were waiting for

A surprising amount of code in our trade fair pipeline has nothing to do with the actual job. Job tracking in DynamoDB, so we know which stage a fair is stuck in. Backoff and retries. Handing work over to the fallback agent when the primary agent runs out of budget. Every stage is its own Lambda, wired together with SQS, because a single function gets killed after 15 minutes.

Durable Functions (available since December 2025) go straight at that problem. You write the workflow as plain code and wrap units of work in step calls. Lambda persists the result of every step. If the function crashes or waits, it gets invoked again later and skips everything that already completed. You pay no compute while it waits.

import { withDurableExecution, DurableContext } from "@aws/durable-execution-sdk-js";
import { runPrimaryAgent, runFallbackAgent, saveResult } from "./agents";

export const handler = withDurableExecution(
  async (event: { fairId: string }, context: DurableContext) => {
    let result = await context.step("primary-agent", async () =>
      runPrimaryAgent(event.fairId),
    );

    // Only branches on a step's stored result, so it's safe to replay
    if (!result.complete) {
      result = await context.step("fallback-agent", async () =>
        runFallbackAgent(event.fairId, result),
      );
    }

    await context.step("save", async () => saveResult(event.fairId, result));
    return { fairId: event.fairId, status: result.status };
  },
);

The queues between the agent stages, their dead-letter queues (DLQs) and the status table collapse into one function. That’s what sold us.

The catch is the same one Temporal and Azure Durable Functions have: replay. When the function resumes, your code runs from the top again, and only the steps are served from stored state. AWS is blunt about it: code outside a step must be a pure function of the input and the results of completed steps. A Date.now(), a Math.random() or a freshly generated UUID in your control flow returns a different value on replay, and your code takes a different branch than it did the first time. These bugs are hard to track down because they only show up when a replay actually happens.

The second catch surprised us, because it’s exactly our setup. Durable Functions work with every event source mapping, SQS included. But an event source mapping (ESM) invokes the function synchronously, and that caps the entire execution at 15 minutes, across all replays. If you need longer, put a small starter Lambda in front that invokes the durable function asynchronously. For a pipeline whose fallback agent keeps iterating until the data is complete, that’s not a footnote.

The rest of what you should know:

  • New functions only. DurableConfig is set at creation time; you can’t switch an existing function over. Invocations always need a qualified ARN (Amazon Resource Name, pointing to a version or alias), and a running execution stays pinned to its version.
  • ExecutionTimeout is mandatory and caps total duration at 366 days. The usual timeout of up to 15 minutes still applies to each invocation.
  • DLQs yes, Lambda Destinations no. If your error handling depends on Destinations, you’ll have to rework it. Lambda also doesn’t retry failed asynchronous durable executions for you.
  • Idempotency only at the start. Passing a DurableExecutionName on invoke stops the same event from starting two executions (for us, that would be the fair ID). Steps themselves run at least once by default, so the code inside them has to be idempotent. ESMs can’t pass an execution name, which is one more reason for the starter Lambda.
  • Cost: $8 per million durable operations (starting an execution, each step and each wait count as one), plus $0.25 per GB of state written and $0.15 per GB-month retained. The compute for replays comes on top. For a pipeline with a handful of long steps, that’s noise. With thousands of tiny steps per execution, do the math first.
  • SDKs exist for TypeScript/JavaScript, Python, Java (GA since April 2026), Go and .NET.

Durable Functions or Step Functions? If the workflow is mostly code and one team owns it: Durable Functions. If you’re orchestrating lots of AWS services without much code of your own, if ops wants to see the state of each execution visually, or if non-developers need to follow the flow: Step Functions. For our agent pipeline we’d go with Durable Functions. “Run the primary agent, fall back to the iterative one with a cap on iterations” reads better in TypeScript than in ASL (Amazon States Language).

Managed Instances: Lambda on your own EC2 instances

Managed Instances (since late November 2025) run Event Functions on EC2 instances in your account. AWS handles OS patching, load balancing and scaling. You pick instance types and a memory-to-vCPU ratio (2:1, 4:1 or 8:1). Programming model and triggers stay the same. Since March 2026 you can go up to 32 GB and 16 vCPUs, and scheduled scaling arrived in May.

The pricing tells you who this is for: the EC2 price, plus a 15% management fee on the on-demand price, plus $0.20 per million requests. Savings Plans and Reserved Instances apply to the EC2 part. So it makes sense for steady, high load where you already have compute discounts, or for workloads that need a CPU-to-memory ratio standard Lambda won’t give you. No GPUs.

What you give up:

  • Scale to zero. With no traffic, the function sits at its configured minimum, which defaults to three instances for resilience across Availability Zones (AZs). You only get to zero on a schedule.
  • One request per environment. An environment handles several invocations at once, via threads, workers or (on Python) multiple processes sharing /tmp, depending on the runtime. Code that assumes module-level globals belong to a single request will break. The docs say it plainly: your code must be thread-safe.
  • Fast scale-out. Scaling reacts asynchronously to CPU load. If traffic more than doubles within five minutes, you can get throttled.

For the trade fair platform: no. Our load comes in bursts, when fairs get added or a new season starts, and not much happens in between. That’s exactly what standard Lambda is built for.

Tenant isolation mode

For SaaS builders: since November 2025, Lambda can isolate execution environments per tenant. The caller passes a tenant ID, and an environment that served tenant A never sees a request from tenant B. If you’ve been deploying one function per tenant to get that guarantee, you can stop.

The limits are real, though. You can only enable it when you create the function, and it doesn’t combine with function URLs, provisioned concurrency, SnapStart or Managed Instances. Event source mappings can’t pass a tenant ID either. AWS’s answer is a router Lambda that reads the ID from the SQS message or EventBridge event and invokes the isolated function with it. If you only separate tenants at the data layer (we do it in the DynamoDB schema), you probably don’t need this.

Smaller changes that kill old workarounds

None of these deserves its own post. Together they clean up a lot of things we’ve been carrying around in projects for years:

  • 1 MB payloads instead of 256 KB for SQS (August 2025), asynchronous Lambda invocations (October 2025) and EventBridge (January 2026). You no longer need the claim-check pattern (put the payload in S3, send only the key) for anything up to 1 MB. Each 64 KB chunk above 256 KB is billed as an extra request, though.
  • Response streaming up to 200 MB instead of 20 MB, in all commercial regions since April 2026. Still Node.js and custom runtimes only.
  • Provisioned mode for SQS event source mappings (November 2025): dedicated pollers with a minimum and maximum, billed per event poller unit. Useful if you don’t want to wait minutes for scaling after a traffic spike. Since August you can have up to 10,000 pollers per ESM.
  • Self-managed code storage (July 2026): with S3ObjectStorageMode=REFERENCE, Lambda reads your code straight from your own S3 bucket, with no copy and no storage quota. The default quota for Lambda-managed code storage also went from 75 GB to 300 GB per region. If you’ve ever had to debug a deployment failing with CodeStorageExceededException, you’ll appreciate it.
  • Metadata endpoint (March 2026): a function can look up its AZ ID (something like euc1-az2) and send requests to the database replica or cache in the same AZ. Less latency, less cross-AZ traffic.
  • S3 Files (April 2026): mount S3 buckets into Lambda as a file system over NFS. The function has to run in a VPC, and it doesn’t work with Managed Instances.
  • New runtimes: Python 3.14 and Node.js 24 (November 2025; Node 24 drops callback-style handlers), Rust GA (November 2025), .NET 10 (January 2026), Ruby 4.0 (April 2026). Node.js 26 and Python 3.15 have been in public preview since August, with GA announced for November.
  • Remote debugging from VS Code (July 2025) against a real Lambda in AWS, through the AWS Toolkit and IoT Secure Tunneling. Sounds like a gimmick until you hit a bug that only reproduces with real IAM permissions inside a real VPC.

One claim that got passed around a lot last year: “Lambda doesn’t need a NAT Gateway anymore.” There’s no new feature behind it, just an AWS blog post on IPv6 from November 2025. Lambda in a dual-stack VPC has been able to reach the internet through a free egress-only internet gateway since 2023. That only helps for destinations that speak IPv6. For IPv4-only APIs, or when you need fixed outbound IPs, you still need the NAT Gateway.

Web Functions: The Lambda we wanted in 2020

Web Functions launched on October 12 and are the biggest conceptual change of the bunch. Your code is a regular HTTP server; Express or Hono run without an adapter. No handler, no JSON event, no serverless-http. One environment serves up to 128 requests at the same time.

We haven’t run Web Functions ourselves yet. What follows comes from the AWS docs and from Ben Steele’s very thorough notes, who took the runtime apart. He calls it “the Lambda I wanted in 2020.” We agree, for a reason the launch posts mostly skip over: the billing model.

Why billing is the real story

Standard Lambda bills wall-clock time multiplied by configured memory. If your function waits eight seconds for an LLM response, you pay for eight seconds. That never mattered when the slowest thing was a 20 ms database call. For applications that spend their life waiting on model APIs, it’s the biggest line on the bill.

Web Functions bill active CPU time plus the memory you actually use over the environment’s lifetime. Here’s a back-of-the-envelope comparison using us-east-1 prices, for an endpoint that waits 8 seconds on an LLM per request and burns 50 ms of CPU doing it, at one million requests a month:

Event Function (arm64, 512 MB) Web Function
Requests $0.20 $0.30
Compute 1M × 8 s × 0.5 GB × $0.0000133334 ≈ $53.30 1M × 0.05 vCPU-s × $0.0000276944 ≈ $1.40
Memory included in compute one environment, 200 MB used, full month × $0.0000036667/GB-s ≈ $1.90
Total ≈ $53.50 ≈ $3.60

The assumptions are deliberately simple: steady load (about three concurrent requests on average, which one environment handles easily) and no data transfer. Real traffic spikes mean more environments and a bigger memory share, since idle time is billed too. The order of magnitude holds anyway: for I/O-bound endpoints, you’re looking at 10x or more. The flip side: for short, CPU-heavy requests, Web Functions aren’t automatically cheaper. The per-request price is 50% higher than standard Lambda.

For the trade fair platform, this only helps partway. The agents sit behind SQS, and Web Functions are invoked through their HTTPS endpoint only. No SQS consumer, no S3 trigger. AWS explicitly recommends Event Functions for anything event-driven. It’s a clean split: Web Functions for anything a person or another service calls over HTTP, Event Functions for everything behind that.

What will bite you when you move over

The launch limitations are significant, and some aren’t obvious:

  • Node.js 24 on arm64 only, a fixed 2 vCPUs and 2 GB per environment, five regions (us-east-1, us-east-2, us-west-2, Tokyo, Ireland). No Frankfurt. Python, Java and .NET teams stay on Event Functions for now.
  • Code only from versioned S3. aws lambda-web deploy uploads a local folder for you, but under the hood a zip in a versioning-enabled S3 bucket is the only way in. Pipelines built on update-function-code --zip-file need rework. Delete the object version and the revision is broken for good.
  • No Lambda extensions. The AWS docs don’t mention it either way, but Steele checked: the extensions and telemetry APIs return 404. So Datadog, secrets caching or OpenTelemetry via Lambda extensions are out, and telemetry has to be shipped from inside your process.
  • Shared state. Many requests share one Node process. A module-level cache, a request context stored in a global, or a singleton holding user data was harmless on standard Lambda. Now it leaks between requests from different users. That’s the bug we’d most expect when porting existing functions.
  • One second after SIGTERM. Then the process is gone. Graceful shutdown with long flushes won’t work. Your server also has to be listening on its port within 10 seconds of starting.
  • Idle costs money. Memory is billed over the environment’s whole lifetime. AWS doesn’t document an idle timeout; Steele saw an unused environment get torn down after about five minutes.
  • Logs, multiplied. There’s one log group per region plus a central one in the home region, both set to never expire by default. With a multi-region endpoint across three regions, every log line is stored four times. Set retention right away.
  • HTTP/1.1 only, no WebSockets. The Upgrade header is stripped, and Lambda forwards the full request body before your response can start. Response streaming works, and with it server-sent events.

Steele also found that setting maxEnvironments produced 429 errors under bursty load (Platform.EndpointMaxEnvThrottle), while leaving it unset let the platform over-provision generously. 429s aren’t queued. If you cap environments to control cost, load test that first.

In return you get multi-region with latency-based routing behind a global URL, immutable revisions with weighted canaries, and VPC access through network connectors. That’s a lot for a first release.

MicroVMs: Not Lambda as you know it

Lambda MicroVMs (since June 2026) share little with standard Lambda beyond Firecracker and the name. You get an isolated, stateful VM built from a Dockerfile, with its own HTTPS endpoint (HTTP/2, gRPC, WebSockets) and up to 8 hours of runtime. Suspend and resume keep memory and disk state, and the next request wakes the VM back up. By default it starts with 1 vCPU and 2 GB and bursts up to 4 vCPUs and 8 GB when needed.

What’s missing is horizontal scaling. The model is one VM per user or session, and you start each one yourself with run-microvm. AWS says you can launch several hundred per minute, but the orchestration is yours to build: who gets which VM, when to suspend, when to terminate. Every inbound connection also needs an auth token that you mint through the API.

The use case is narrow and clear: running code you didn’t write. Code interpreters for agents, sandboxes for user plugins, notebooks, coding agents that check out a repository and run its tests. To reach your own VPC there are network connectors in the new Lambda Core API: create the elastic network interfaces (ENIs) once (that takes around ten minutes) and attach them when you launch a MicroVM. Internet access works without one.

The obvious alternative is Bedrock AgentCore Runtime. There’s no official comparison. Yan Cui puts it this way: AgentCore Runtime is to MicroVMs what Fargate is to EC2. AgentCore handles routing, scaling, auth and versioning for you; MicroVMs give you control over the image, the network and the lifecycle, plus suspend/resume. If you want to run an agent, AgentCore gets you there faster. If you’re building a sandbox platform, use MicroVMs.

The trade fair platform doesn’t need MicroVMs. Our fallback agent is our own code, not untrusted input. It runs as a container image because of the size of its dependencies, not for security reasons.

Which one for what?

Workload Our pick Alternative if …
Async, event-driven pipeline Event Function —
Multi-step workflow with retries, waits, fallbacks Event Function + Durable Functions (with a starter Lambda behind SQS) Step Functions, if you orchestrate many services with little code or need visual monitoring
User-facing API, SSR, I/O-bound Web Function Event Function + function URL if you’re not on Node.js or your region is missing; Fargate if you need WebSockets
Steady, sustained load with Savings Plans in place Event Function on Managed Instances Fargate/ECS if you already run containers
Untrusted or AI-generated code MicroVMs Bedrock AgentCore if it’s an agent rather than a sandbox platform
GPUs, runtimes beyond 8 hours Not Lambda ECS/EC2, SageMaker

What we’d build differently today

Honestly: less than the volume of announcements suggests.

We’d replace the SQS chain between the agent stages with one durable function, kicked off by a thin Lambda that passes the fair ID as the execution name. That saves infrastructure, but mostly it removes code that only exists because Lambda couldn’t remember anything across invocations. The user-facing API would be a candidate for Web Functions once they’re available in Frankfurt and we no longer depend on extensions for observability. Everything else stays as it is. The pipeline is bursty, event-driven and stateless, and standard Lambda has always been good at that.

Each of the new primitives solves one specific problem that a lot of teams have been working around. If you don’t have any of those problems, there’s nothing to do. If you do, now is a good time to check whether your workaround still needs to exist.

Cookies