New Feature: I tried running a Flask app on AWS Lambda MicroVMs and tested suspend and resume
This page has been translated by machine translation. View original
Introduction
On June 22, 2026, Lambda MicroVMs were announced as a new computing primitive for AWS Lambda.
Lambda MicroVMs is a serverless environment that can run user- or AI-generated code with VM-level isolation. Based on Firecracker virtualization technology, it provides fast startup from snapshots and stateful suspend/resume capabilities.
Here is a comparison of how Lambda MicroVMs differ from traditional Lambda functions.
| Aspect | Lambda Functions | Lambda MicroVMs |
|---|---|---|
| Design philosophy | Event-driven, stateless | Stateful isolated sandbox |
| Isolation | Firecracker MicroVM (with reuse) | Firecracker MicroVM (isolated per instance) |
| State retention | Not guaranteed | Memory and disk state retained during suspend |
| Maximum execution time | 15 minutes | 8 hours |
| Resource limits | Up to 6 vCPU / 10 GB memory | Up to 16 vCPU / 32 GB memory / 32 GB disk |
| Lifecycle control | Managed by AWS | Explicitly controlled by developer |
| Connection method | Event source / Function URL | Dedicated HTTPS endpoint |
Lambda MicroVMs is not a replacement for existing Lambda functions, but is suited for scenarios that require long-running, interactive environments isolated per user.
In this article, we run the Flask app sample from the official blog in ap-northeast-1 (Tokyo) and verify the lifecycle. The S3 bucket name is represented as YOUR-BUCKET-NAME and the account ID as 123456789012.
AWS CLI version 2.35.10 was used (a version that supports the lambda-microvms subcommand is required).
Verification
Creating an IAM Role
We create an IAM role to be used during Lambda MicroVMs image builds. The Lambda service assumes this role to retrieve code from S3 and output build logs to CloudWatch Logs.
Trust policy:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": ["sts:AssumeRole", "sts:TagSession"]
}]
}
aws iam create-role \
--role-name MicroVMBuildRole \
--assume-role-policy-document file://trust-policy.json
Permission policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
aws iam put-role-policy \
--role-name MicroVMBuildRole \
--policy-name MicroVMBuildPolicy \
--policy-document file://build-policy.json
Preparing the Sample App & Uploading to S3
Prepare three files: the Flask app, Dockerfile, and requirements.txt.
app.py:
import logging
from flask import Flask, jsonify
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
@app.route("/")
def hello():
app.logger.info("Received request to hello world endpoint")
return jsonify(message="Hello, World!")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
requirements.txt:
flask==3.1.1
gunicorn==23.0.0
Dockerfile:
FROM public.ecr.aws/lambda/microvms:al2023-minimal
RUN dnf install -y python3 python3-pip && dnf clean all
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app"]
gunicorn listens on 0.0.0.0:8080. Since port 8080 is specified in the auth token's allowed-ports and in X-aws-proxy-port when making requests, the application's listening port is also set to 8080.
Create an S3 bucket, package the files into a zip archive, and upload it.
aws s3 mb s3://YOUR-BUCKET-NAME --region ap-northeast-1
zip app.zip app.py requirements.txt Dockerfile
aws s3 cp app.zip s3://YOUR-BUCKET-NAME/app.zip
Creating a MicroVM Image
Use create-microvm-image to create the image. The flow involves executing the Dockerfile, starting the application, and capturing a Firecracker snapshot of that state.
--base-image-arn specifies the VM infrastructure provided by Lambda MicroVMs, and has a different role from the OS/application environment specified by FROM in the Dockerfile.
aws lambda-microvms create-microvm-image \
--name flask-microvm-demo \
--code-artifact uri=s3://YOUR-BUCKET-NAME/app.zip \
--base-image-arn arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 \
--build-role-arn arn:aws:iam::123456789012:role/MicroVMBuildRole \
--region ap-northeast-1
{
"imageArn": "arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:flask-microvm-demo",
"name": "flask-microvm-demo",
"state": "CREATING",
"baseImageArn": "arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1",
"codeArtifact": {
"uri": "s3://YOUR-BUCKET-NAME/app.zip"
},
"imageVersion": "1.0"
}
Poll and wait for the build to complete.
while true; do
STATE=$(aws lambda-microvms get-microvm-image \
--image-identifier arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:flask-microvm-demo \
--region ap-northeast-1 --query 'state' --output text)
echo "$(date +%H:%M:%S) $STATE"
[ "$STATE" = "CREATED" ] && break
sleep 10
done
The build transitioned to CREATED in approximately 3 minutes.
{
"imageArn": "arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:flask-microvm-demo",
"name": "flask-microvm-demo",
"state": "CREATED",
"latestActiveImageVersion": "1.0",
"createdAt": "2026-06-23T10:11:30.953000+09:00",
"updatedAt": "2026-06-23T10:14:31.702000+09:00"
}
Launching the MicroVM
Use run-microvm to launch the MicroVM. Specify the ingress/egress network connectors and idle policy.
aws lambda-microvms run-microvm \
--image-identifier arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:flask-microvm-demo \
--ingress-network-connectors "arn:aws:lambda:ap-northeast-1:aws:network-connector:aws-network-connector:ALL_INGRESS" \
--egress-network-connectors "arn:aws:lambda:ap-northeast-1:aws:network-connector:aws-network-connector:INTERNET_EGRESS" \
--idle-policy '{"autoResumeEnabled":true,"maxIdleDurationSeconds":900,"suspendedDurationSeconds":300}' \
--region ap-northeast-1
{
"microvmId": "microvm-01234567-abcd-ef01-2345-6789abcdef01",
"state": "PENDING",
"endpoint": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.lambda-microvm.ap-northeast-1.on.aws",
"idlePolicy": {
"maxIdleDurationSeconds": 900,
"suspendedDurationSeconds": 300,
"autoResumeEnabled": true
},
"maximumDurationInSeconds": 28800
}
The meaning of each idle policy parameter is as follows.
| Parameter | Value Used | Meaning |
|---|---|---|
maxIdleDurationSeconds |
900 | Number of seconds of idle time before suspending |
suspendedDurationSeconds |
300 | Maximum number of seconds to remain in suspended state |
autoResumeEnabled |
true | Whether to automatically resume upon receiving a request |
The MicroVM transitioned to RUNNING in approximately 10 seconds. Because startup is based on snapshot restoration rather than re-running application initialization each time, the environment is expected to be ready for use immediately after startup.
aws lambda-microvms get-microvm \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--region ap-northeast-1 --query 'state' --output text
RUNNING
Sending HTTP Requests
Requests to the MicroVM require an auth token. Obtain one using create-microvm-auth-token.
TOKEN=$(aws lambda-microvms create-microvm-auth-token \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--expiration-in-minutes 30 \
--allowed-ports '[{"port":8080}]' \
--region ap-northeast-1 \
--query 'authToken."X-aws-proxy-auth"' --output text)
Send a request with the token attached as the X-aws-proxy-auth header.
curl "https://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.lambda-microvm.ap-northeast-1.on.aws/" \
-H "X-aws-proxy-auth: $TOKEN" \
-H "X-aws-proxy-port: 8080"
{"message":"Hello, World!"}
Suspend & Resume
Use suspend-microvm to manually suspend the MicroVM.
aws lambda-microvms suspend-microvm \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--region ap-northeast-1
aws lambda-microvms get-microvm \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--region ap-northeast-1 --query 'state' --output text
SUSPENDED
Send a request again while in the suspended state. Since autoResumeEnabled: true is set in the idle policy, receiving a request will trigger an automatic resume.
time curl "https://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.lambda-microvm.ap-northeast-1.on.aws/" \
-H "X-aws-proxy-auth: $TOKEN" \
-H "X-aws-proxy-port: 8080"
{"message":"Hello, World!"}
real 0m2.636s
The time from sending the request in the suspended state to receiving the response was approximately 2.6 seconds (based on curl's real time, including network round-trip and TLS establishment). Note that this is not the resume processing time alone. The auth token was still within its 30-minute validity period, and requests succeeded with the same token across the suspend/resume cycle.
Confirm that the state has returned to RUNNING.
aws lambda-microvms get-microvm \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--region ap-northeast-1 --query 'state' --output text
RUNNING
Cleanup
After completing verification, delete the created resources.
# Terminate the MicroVM
aws lambda-microvms terminate-microvm \
--microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
--region ap-northeast-1
# Delete the MicroVM image
aws lambda-microvms delete-microvm-image \
--image-identifier arn:aws:lambda:ap-northeast-1:123456789012:microvm-image:flask-microvm-demo \
--region ap-northeast-1
# Delete S3 objects and bucket
aws s3 rm s3://YOUR-BUCKET-NAME --recursive
aws s3 rb s3://YOUR-BUCKET-NAME
# Delete IAM role (delete inline policy first, then delete the role)
aws iam delete-role-policy --role-name MicroVMBuildRole --policy-name MicroVMBuildPolicy
aws iam delete-role --role-name MicroVMBuildRole
Summary
| Step | Time Required |
|---|---|
| Image build | Approximately 3 minutes |
| MicroVM startup (PENDING → RUNNING) | Approximately 10 seconds |
| Resume from suspend + response | Approximately 2.6 seconds |
Unlike traditional Lambda function deployments, the flow here involved defining the application environment with a Dockerfile and capturing a snapshot, but the steps were straightforward with no confusing parts. Because startup is based on snapshot restoration, there is no need to redo initialization on each start, and the execution environment can be resumed without redeployment via suspend/resume.
The official blog mentions AI coding assistant sandboxes and multi-tenant code execution environments as intended use cases. Given the characteristic that memory and disk state are preserved across suspends, this seems well-suited for workloads that spin up isolated environments per user session and need to pause and resume them.
