# AWS Lambda Web Adapter: Run Express, FastAPI or Next.js on Lambda Without Rewriting

> The Lambda Web Adapter is a Rust extension that sits between the Lambda runtime API and your HTTP app, translating events into HTTP requests. It is for teams that already have a working web server and want Lambda without adopting a handler-based framework.

**aws/aws-lambda-web-adapter** — Run web applications on AWS Lambda

- Repository: https://github.com/aws/aws-lambda-web-adapter
- Stars: 2,749 · Forks: 162
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/aws-aws-lambda-web-adapter

## What the adapter actually solves for HTTP apps on Lambda

Lambda's native programming model is event-driven: a handler receives an event object and returns a value. Frameworks like Express.js, Next.js, Flask, SpringBoot, ASP.NET and Laravel expect the opposite: a long-lived process listening on a port, receiving HTTP 1.1/1.0 requests. Bridging the two usually means adopting a framework-specific shim, or rewriting routing and middleware.

The adapter removes that step. According to the README, it allows developers to build web apps with familiar frameworks and run them on Lambda, and it states that no new code dependency is required in the application. The same Docker image can run on AWS Lambda, Amazon EC2, AWS Fargate, and local computers. That last property is the real pitch: one artifact, several runtimes, no Lambda-specific code path inside the app.

It supports Amazon API Gateway REST and HTTP APIs, Lambda Function URLs, and Application Load Balancer, plus Lambda managed runtimes, custom runtimes and Docker OCI images. It is not a framework and not a router. It is a translation layer that happens to be written in Rust and shipped as a Lambda extension or layer.

## How the adapter sits between the runtime API and your server

The adapter runs as a Lambda extension. It polls the Lambda runtime API for the next invocation, converts the incoming event into an HTTP request, and forwards that request to your application on the traffic port. The response is converted back into the Lambda response format.

The traffic port defaults to 8080 and is set with AWS_LWA_PORT, which falls back to PORT. Before forwarding traffic, the adapter performs a readiness check against AWS_LWA_READINESS_CHECK_PATH (default "/") on AWS_LWA_READINESS_CHECK_PORT (defaulting to the traffic port), using either HTTP or TCP as set by AWS_LWA_READINESS_CHECK_PROTOCOL. Which HTTP status codes count as healthy is configurable through AWS_LWA_READINESS_CHECK_HEALTHY_STATUS, defaulting to "100-499".

Several behaviours are opt-in rather than automatic. Compression via AWS_LWA_ENABLE_COMPRESSION applies only in buffered mode. Response streaming requires AWS_LWA_INVOKE_MODE set to response_stream. Non-HTTP triggers are routed to the path in AWS_LWA_PASS_THROUGH_PATH, default "/events". The adapter also manages its own keep-alive connection to your app, with AWS_LWA_POOL_IDLE_TIMEOUT_SECONDS defaulting to 4 seconds; setting it to 0 disables connection reuse entirely.

## Installing the adapter as a container extension

The Docker path is one line in a Dockerfile. The README gives this example, copying the adapter binary out of the public ECR image into the extensions directory:

```dockerfile
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.1.0 /lambda-adapter /opt/extensions/lambda-adapter
```

Pre-compiled multi-arch images for x86_64 and arm64 are published at public.ecr.aws/awsguru/aws-lambda-adapter. The README notes that non-AWS base images may be used because the Runtime Interface Client ships with the adapter.

After the image is built and pushed, the function needs the usual container image configuration plus the port setting. The configuration table in the README lists AWS_LWA_PORT, which defaults to "8080", and AWS_LWA_READINESS_CHECK_PATH, which defaults to "/". Both are defined as Lambda function configuration, and the README states they can also be set within the Dockerfile.

On the first invocation the adapter performs a readiness check against that path and then forwards the request to your server. If the app never reports ready, the invocation fails rather than serving a partial response.

## Zip packages, layers and the bootstrap wrapper

For zip-based functions the README gives three steps. Attach the Lambda Web Adapter layer, using arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:30 for x86_64 or arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerArm64:30 for arm64. Set the environment variable AWS_LAMBDA_EXEC_WRAPPER to /opt/bootstrap. Set the function handler to your startup script, for example run.sh.

That third step is where most first attempts break. The handler is not a function name; it is the script that starts your web server. The README points to a separate Zip Packages guide that covers AWS China region ARNs and Windows caveats, which suggests the Windows path has enough differences to warrant its own documentation.

The layer version in those ARNs is 30, while the container example pins image tag 1.1.0. Those are different versioning schemes for the same project, so a deployment that mixes the two will not be running identical builds.

## Where the adapter is the wrong tool

The readiness check has a failure mode worth reading twice. AWS_LWA_READINESS_CHECK_TIMEOUT_SECONDS controls how long the adapter waits for the app to report ready during cold-start initialization and after a SnapStart restore. On expiry the adapter fails: initialization fails and the runtime never starts, or a restore fails. The default is unset, and unset, 0 or negative all mean wait indefinitely. A set-but-nonpositive or malformed value is ignored with a warning. So a misconfigured timeout silently becomes an unbounded wait, which is the opposite of what someone setting a timeout intends.

AWS_LWA_ASYNC_INIT is explicitly ignored under SnapStart and Provisioned Concurrency, and it keeps its own roughly 9.8 second bound. If your initialization is long and you rely on SnapStart, async init is not the lever you think it is.

Compression only applies in buffered mode, so a streaming function cannot use it. And the adapter is not a library: Cargo.toml sets publish = false, with a comment stating the lib target is an internal implementation detail with no external API-stability contract. If you wanted to embed this logic in a Rust service, the project deliberately does not support that. Teams that need fine-grained control over event shapes, or that already have a clean handler-based Lambda, gain nothing here.

## How it differs from Mangum and framework shims

Mangum is the comparison people reach for with FastAPI. Mangum is a Python library that wraps an ASGI application and exposes it as a Lambda handler. Your code imports it, and the handler is a Python function. Lambda Web Adapter takes the opposite approach: your application is unchanged and still binds a port, and the translation happens outside the process, in a separate binary running as a Lambda extension.

The practical difference is portability. A Mangum-wrapped app is a Lambda app. An adapter-backed app is a web app that Lambda happens to run, which is why the README can claim the same Docker image runs on EC2, Fargate and a local machine. The cost is an extra process, a readiness handshake, and configuration that lives in environment variables rather than in application code. It also means the adapter's behaviour applies to every framework in the same way, which is why the examples directory contains parallel entries for Express.js, FastAPI, ASP.NET, Deno, Bun and Datadog rather than one integration per framework.

## SnapStart hooks, licensing and the cost of staying current

For SnapStart, the adapter can notify the application at the snapshot boundary so it can drain and re-establish state such as database connections, cached DNS, PRNG seeds and unique identifiers. Two opt-in variables control this: AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATH, which the adapter POSTs to before a snapshot, and AWS_LWA_SNAPSTART_AFTER_RESTORE_PATH, which it POSTs to after a restore. Both are independent and neither is enabled by default. The README does not document rollback behaviour for these hooks, so an app that fails to drain cleanly at checkpoint is an application-level concern.

Upgrade cost is mostly configuration debt. The README carries a deprecation notice: HOST, READINESS_CHECK_PORT, READINESS_CHECK_PATH, READINESS_CHECK_PROTOCOL, REMOVE_BASE_PATH and ASYNC_INIT are non-namespaced variables scheduled for removal in version 2.0. PORT is not deprecated and remains a supported fallback for AWS_LWA_PORT. Separately, AWS_LWA_READINESS_CHECK_MIN_UNHEALTHY_STATUS was removed in 1.0 in favour of AWS_LWA_READINESS_CHECK_HEALTHY_STATUS. Any function still setting the old names will need edits before a 2.0 upgrade.

The project is licensed Apache-2.0, and the repository includes a NOTICE file alongside the LICENSE, which is the usual arrangement for Apache-2.0 distributions. If you redistribute the adapter inside your own image, read those two files rather than assuming the licence text alone tells the whole story. This is not legal advice.

On maintenance: the repository is not archived, and the last push was on 2026-09-18, the same day as the v1.1.0 release. The prior release, v1.0.1, was on 2026-05-28, and v1.0.0 on 2026-03-27.

## Conclusion

Adopt it if you have a working HTTP server (FastAPI, Express.js, SpringBoot, ASP.NET, Laravel) and want Lambda without rewriting handlers, especially if the same Docker image must also run on EC2 or Fargate. Do not adopt it if you need the crate as a library dependency: Cargo.toml sets publish = false, so the adapter ships only as the lambda-adapter binary, layer or extension. Before committing, verify the readiness check path and protocol against your app, confirm whether AWS_LWA_INVOKE_MODE must be response_stream for your framework, and check which deprecated non-namespaced variables you still set, because they are scheduled for removal in version 2.0.

## FAQ

### What is AWS Lambda Web Adapter used for?

It runs HTTP 1.1/1.0 web applications on AWS Lambda without adding a code dependency to the application. The README lists Express.js, Next.js, Flask, SpringBoot, ASP.NET and Laravel as examples, and says the same Docker image can also run on EC2, Fargate and a local computer.

### How do I install AWS Lambda Web Adapter in a Docker image?

Add one COPY line to your Dockerfile that pulls /lambda-adapter from public.ecr.aws/awsguru/aws-lambda-adapter into /opt/extensions/lambda-adapter. Pre-compiled multi-arch images for x86_64 and arm64 are published in that same public ECR repository.

### Can I use AWS Lambda Web Adapter with FastAPI?

Yes. The repository ships a FastAPI example directory, including variants for response streaming, background tasks, SnapStart and zip packaging. Your FastAPI app keeps listening on a port, and the adapter forwards Lambda invocations to it.

### What is the AWS Lambda Web Adapter layer ARN?

The README gives arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:30 for x86_64 and arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerArm64:30 for arm64. It also points to a Zip Packages guide covering AWS China region ARNs and Windows caveats.

### Does AWS Lambda Web Adapter support response streaming?

Yes, but it is opt-in. You set AWS_LWA_INVOKE_MODE to response_stream; the default is buffered. Response compression via AWS_LWA_ENABLE_COMPRESSION applies only in buffered mode.

### Is AWS Lambda Web Adapter available as a Rust crate?

No. Cargo.toml sets publish = false, with a comment explaining that the lib target is an internal implementation detail of the binary and tests with no external API-stability contract. New development ships only as the lambda-adapter binary, layer or extension.

## Sources

- [aws/aws-lambda-web-adapter on GitHub](https://github.com/aws/aws-lambda-web-adapter)
- [Issues](https://github.com/aws/aws-lambda-web-adapter/issues)
- [License: Apache-2.0](https://github.com/aws/aws-lambda-web-adapter/blob/main/LICENSE)
- [README](https://github.com/aws/aws-lambda-web-adapter/blob/main/README.md)
- [Releases](https://github.com/aws/aws-lambda-web-adapter/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/aws-aws-lambda-web-adapter
