New Feature: I Tried Running a Flask App on AWS Lambda MicroVMs and Even Tested Suspend and Resume
ちょっと話題の記事

New Feature: I Tried Running a Flask App on AWS Lambda MicroVMs and Even Tested Suspend and Resume

I actually ran the new AWS Lambda feature MicroVMs in the Tokyo region. I confirmed the entire lifecycle via CLI, including image creation from a Dockerfile, MicroVM startup, HTTP requests, and suspend/resume operations.
2026.06.23

This page has been translated by machine translation. View original

Introduction

On June 22, 2026, Lambda MicroVMs was announced as a new computing primitive for AWS Lambda.

https://aws.amazon.com/jp/about-aws/whats-new/2026/06/aws-lambda-microvms/

Lambda MicroVMs is a serverless environment that can execute code generated by users or AI with VM-level isolation. Based on Firecracker virtualization technology, it provides fast startup from snapshots and stateful suspend/resume capabilities.

Here is a summary of how it differs from traditional Lambda functions in terms of positioning.

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 suspension
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 AWS managed 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 requiring long-running interactive environments isolated per user.

In this article, we will run the Flask app sample from the official blog in ap-northeast-1 (Tokyo) and verify the lifecycle. Throughout the article, 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).

https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html

Verification

Creating an IAM Role

We will create an IAM role to be used when building Lambda MicroVMs images. 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: a Flask app, a 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"]

The app listens on 0.0.0.0:8080 with gunicorn. Since 8080 is specified in the auth token's allowed-ports and in X-aws-proxy-port when making requests, the app's listening port is also set to 8080.

Create an S3 bucket, package everything into a zip file, 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 an image. The flow involves running the Dockerfile, starting the application, and then taking a Firecracker snapshot of that state.

--base-image-arn specifies the VM infrastructure provided by Lambda MicroVMs, and its role differs 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 to 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"
}

Starting the MicroVM

Use run-microvm to start 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 Description
maxIdleDurationSeconds 900 Number of seconds of continued idle before suspending
suspendedDurationSeconds 300 Maximum number of seconds to remain in suspended state
autoResumeEnabled true Whether to automatically resume upon receiving a request

Startup transitioned to RUNNING in approximately 10 seconds. Because the restoration method uses a snapshot, it is expected to be immediately available after startup compared to the traditional method of re-running the application initialization process each time.

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

An authentication token is required to send requests to the MicroVM. 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 in 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 another request while in the suspended state. Since autoResumeEnabled: true is configured in the idle-policy, the MicroVM will automatically resume upon receiving a request.

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 a request while in the suspended state to receiving a 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 time for the resume process alone. The authentication token was within its validity period (30 minutes), 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 verification is complete, delete the created resources.

# Terminate MicroVM
aws lambda-microvms terminate-microvm \
  --microvm-identifier microvm-01234567-abcd-ef01-2345-6789abcdef01 \
  --region ap-northeast-1

# Delete 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 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 suspended state + response Approximately 2.6 seconds

Unlike traditional Lambda function deployments, the flow involved defining the application environment with a Dockerfile and taking a snapshot, but the procedure was straightforward with no confusing steps. Because startup uses snapshot restoration, there is no need to redo the initial startup process, and the execution environment can be resumed without redeployment via suspend/resume.

The official blog lists AI coding assistant sandboxes and multi-tenant code execution environments as intended use cases. Given the characteristic that memory and disk state is retained across suspensions, it seems well-suited for workloads that spin up an isolated environment per user session and pause/resume it.

https://dev.classmethod.jp/articles/lambda-microvms-shell-ingress-browser-webshell/

Share this article

AWSのお困り事はクラスメソッドへ