Deciphering How Pre-Release AWS Lambda Web Functions (lambda-web) Work from Publicly Available Sources
ちょっと話題の記事

Deciphering How Pre-Release AWS Lambda Web Functions (lambda-web) Work from Publicly Available Sources

I studied AWS Lambda Web Functions (lambda-web) from the botocore and AWS CLI v2 sources: how to host a Node.js app, the deploy flow, and CloudFront support. The API is unreleased, so this is based on reading source, not running it.
2026.10.04

This page has been translated by machine translation. View original

https://dev.classmethod.jp/articles/aws-lambda-web-functions-ga-express/

Introduction

On October 1, 2026, AWS Lambda Web Functions (lambda-web) was added to botocore and AWS CLI v2 (botocore commit f19f55e01).

In this article, I read the source in the public repositories and organized the resource structure, the deployment mechanism, how endpoints are exposed, and the CloudFront and IAM definitions.

Published Information and Current Status

The changelog for botocore 1.43.107 (October 1, 2026) contains the following statement:

Lambda Web Functions GA launch. Lambda Web Functions enable customers to run web applications and API backends

In botocore 1.43.108 (October 2, 2026) the next day, the following update was made:

Documentation update for AWS Lambda Web Functions, clarifies that the LambdaWeb APIs are experimental and not yet available to external customers.

The AWS CLI 2.37.9 changelog contains the same sentence.

The service description in the service model service-2.json currently begins with the following sentence:

The AWS Lambda Web Functions APIs (LambdaWeb namespace) are experimental and for internal AWS use only. They are not yet available to external customers.

The diff from commit f19f55e01 on October 1 to 3d76b4622 on October 2 is a replacement of 21 lines in a single file, service-2.json. The same note was added to each operation's description and to the service description.

Which of "GA launch" and "experimental ... not yet available" reflects reality cannot be determined from the public source.

Clients for eight languages have been added to the SDKs: JavaScript, Go, Java, Rust, Ruby, PHP, .NET, and C++. The JavaScript SDK commits also followed the same two stages as botocore: the GA launch on October 1 and the experimental note on October 2.

The sources I read are botocore 6197e54b7 (1.43.108) and aws-cli 72c21cc2b (2.37.9). The main references are as follows:

How It Works

Web Function, Revision, and Endpoint

The source is botocore/data/lambda-web/2025-03-07/service-2.json in botocore.

There are three layers of resources. Under the top-level Web Function (WebFunction) are an immutable Revision (WebFunctionRevision) that holds code and configuration, and a WebFunctionEndpoint. A WebFunctionEndpoint is a resource that has a URL exposing the function over HTTPS, and clients send requests to this URL. Hereafter, WebFunctionEndpoint is written as "endpoint."

Each of the three types has create, get, list, and delete APIs, but only the endpoint (UpdateWebFunctionEndpoint) has an update API. To change code or configuration, you create a new Revision and switch the endpoint's target.

When CreateWebFunction succeeds, the status is 202. If you pass revisionConfig and endpointConfig, the initial Revision and endpoint are created at the same time. The model's description says "You don't need separate permissions for the initial revision or endpoint." However, in the IAM definition, CreateWebFunction has iam:PassRole and lambda:PassNetworkConnector attached as required actions (described later). DeleteWebFunction deletes the Revisions and endpoints together.

The only place to put code is S3 (bucket, key, and optional versionId). Searching the entire model turned up no fields corresponding to container images, Docker, handlers, entry points, or architecture.

Execution Model as Seen from a Node.js App

The source for this section is not official documentation but the README.md and AGENTS.md templates generated by aws lambda-web deploy --hello-world.

You can deploy a standard Node.js app that listens on a port without preparing a Lambda-specific adapter or wrapper or rewriting a handler. The server listens on RUNTIME_HTTP_PORT (3000). If it listens on a different port it still becomes Active, but it returns HTTP 502 for requests. It scales with traffic and scales in to zero when idle. Responses are streamed each time the app writes, and no streamifyResponse wrapper is needed.

The architecture is arm64 and cannot be changed in the configuration. Dependency packages that include native binaries need an arm64 build.

The conventional handler-based type is called "Lambda Event Functions." According to the template, a Web Functions project has no exported handler, no event / context arguments, no API Gateway, no Function URL, and no adapter. It is also stated that it is not managed by SAM, CDK, or the aws lambda command.

The default runtime for new creation is defined as nodejs24.x in a CLI constant. The template states that this runtime strips types and runs TypeScript directly, and that transpilation is required if you use features that need code generation, such as enums.

Revision Settings

In CreateWebFunction's revisionConfig, buildConfig and serviceConfig are required.

Item Range / Default
buildConfig.codeConfig.s3Object bucket is 3 to 63 characters, key is 1 to 1024 characters, versionId is optional
buildConfig.runtimeConfig.runtime String (the example in the description is a Node.js runtime identifier)
serviceConfig.executionRoleArn Required
serviceConfig.timeoutSeconds 3 to 900, default 30
serviceConfig.maxConcurrencyPerEnvironment 1 to 128, default 64
serviceConfig.environmentVariables Values are treated as sensitive
serviceConfig.telemetryConfig.loggingConfig The default logGroup is /aws/lambda/web/{functionName}. The default levels for application logs and system logs are both INFO
kmsKeyArn (directly under revisionConfig) KMS key used to encrypt the Revision's code and environment variables

A Revision's state is one of Pending (while building), Active, or Failed.

The Flow of aws lambda-web deploy

The source is awscli/customizations/lambdaweb and awscli/examples/lambda-web/deploy.rst in aws-cli. The AWS CLI 2.37.8 changelog describes the addition of aws lambda-web deploy. This command creates and updates a Web Function from a local HTTP application.

Creation

To generate a starter and deploy it, add --hello-world. To create from an existing HTTP server, pass a directory to --code and skip the confirmation prompt with --create.

aws lambda-web deploy --name my-app --hello-world
aws lambda-web deploy --name my-app --code ./app --create

The documentation explicitly states that the identifiers in the following example output are fictitious.

https://a1b2c3d4e5.x9y.lambda-web.us-east-1.on.aws
Console: https://us-east-1.console.aws.amazon.com/lambda/home#/web-functions/my-app

When no Web Function exists, deploy.py processes in the following order:

  1. Validate the function name and --code. --code is limited to directories, and passing a prebuilt .zip results in an error that points you to create-web-function and create-web-function-revision
  2. Get the account ID with STS GetCallerIdentity
  3. Check for existence with GetWebFunction. If it doesn't exist, proceed to creation; if neither --hello-world nor --create is given, a confirmation prompt appears (it is refused if standard input is not a terminal)
  4. Resolve the entry file and build a ZIP. The ZIP limit is 512 MB, and if it is exceeded the CLI exits with an error without uploading
  5. Check the S3 bucket and create it if it doesn't exist
  6. Check the execution role and create it if it doesn't exist
  7. Upload the ZIP to S3
  8. Call CreateWebFunction. Immediately after role creation, it retries while waiting for IAM propagation
  9. Unless --no-wait is given, it waits until the endpoint becomes Active (the default wait is 600 seconds) and prints the URL to standard output

The name of the execution role the CLI creates is awscli-lambdaweb-<function name> if the function name is 47 characters or fewer (if longer, the function name is truncated and a hash is appended at the end). The S3 bucket name is awscli-lambdaweb-<account ID>-<region>-an. Existing roles and buckets can be specified with --execution-role-arn and --bucket-name, respectively. The settings the CLI applies are shown below.

Execution role and bucket settings created by the CLI

Execution role trust policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Execution role inline policy awscli-lambdaweb-logs

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}

S3 bucket policy (bucket versioning is also enabled)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "HttpsOnly",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::<bucket>",
        "arn:aws:s3:::<bucket>/*"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    },
    {
      "Sid": "AllowLambdaServiceAccess",
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::<bucket>/*",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "<account-id>"
        }
      }
    }
  ]
}

How the Entry File Is Determined

For the entry file, --entry-point is used if given. Otherwise, main in package.json (if the file exists) is checked, then the "." export in exports. If it is still undetermined, it searches in the following order.

index.js → index.mjs → index.cjs
server.js → server.mjs → server.cjs
dist/index.js → dist/server.js
build/index.js → build/server.js

According to the template, the runtime loads index.js by default and does not read package.json. When the determined entry is something other than index.js, an index.js wrapper is added to the ZIP. So that it works for both CJS and ESM projects, the wrapper loads the entry with a dynamic import(). If you set AWS_LAMBDA_NODEJS_ENTRYPOINT yourself, no wrapper is added. Using this environment variable together with --entry-point results in an error.

deploy only zips the --code directory; it does not run npm install, bundling, or compilation. To include node_modules, pass the project root (.) to --code. The same applies to projects that build TypeScript into dist/: pass the project root rather than ./dist to --code, and specify dist/index.js with --entry-point (Example 8 in deploy.rst).

Symbolic links are not followed and are skipped. According to the template, for pnpm or workspace projects, either place real files with npm install or set pnpm's node-linker=hoisted.

The default exclusions include files such as the following.

.git/  .aws/  .ssh/  .env  .env.*  *.pem  *.key  id_rsa*  .npmrc  .netrc

On the other hand, the following hidden directories are included by default.

.next  .nuxt  .svelte-kit  .output  .prisma  .yarn

Updates from the Second Time On

If you run it with the same --name against an existing Web Function, it fetches the latest Revision, carries over the settings, and calls CreateWebFunctionRevision.

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

If --code is omitted, the previous Revision's S3 object is reused, so a Revision with only the settings changed is produced. Environment variables are added or overwritten with --env and removed with --unset-env.

Once the Revision becomes Active, deploy chooses the target endpoint. It is the endpoint given by --endpoint-name if present, otherwise the LatestRevision endpoint, and otherwise the first endpoint. How the chosen endpoint is handled depends on its state.

  • A LatestRevision endpoint follows automatically, so deploy does not update it
  • A Disabled endpoint is repointed to the new Revision with a weight of 100
  • An endpoint whose weight is split across multiple Revisions is left unchanged. When replacing the split, it directs you to use aws lambda-web update-web-function-endpoint

If you pass a non-existent name to --endpoint-name, it creates a new endpoint after confirmation. If there are no endpoints and no name is specified, it deploys only the Revision and does not create an endpoint.

How Endpoints Are Exposed

The source is the service model and the CLI's comments and validation logic.

Item Possible values / Range
endpointType HomeRegion (served from the region where the function was created), MultiRegion (replicated to selected regions and routed to the nearest region), PerRegion (a separate endpoint per region)
regions Required for MultiRegion and PerRegion. Specify at least one region other than the home region
authType ApplicationManaged (authorization on the function side), IamAuth (Lambda authorizes with AWS SigV4 and IAM)
autoDeploymentMode LatestRevision (automatically follows the latest Revision), Disabled (fixed until explicitly changed; the model's default)
revisionWeights 1 to 2 elements. weight is 1 to 100
scalingConfig.maxEnvironments 2 to 10000 (no default)
throttleConfig.rateLimit 0, 100 to 1000 (in steps of 100), 2000 to 10000 (in steps of 1000). The account limit also applies

revisionWeights is described in the model as being for traffic splitting in canary or blue-green deployments.

There are the following constraints on the CLI side for combinations of autoDeploymentMode.

  • LatestRevision cannot take revisionWeights and can be used only with HomeRegion endpoints
  • Disabled requires revisionWeights
  • MultiRegion and PerRegion allow only Disabled

The deploy defaults are endpoint name "dev", HomeRegion, ApplicationManaged, and LatestRevision. With ApplicationManaged, authorization is left to the function side. Lambda authorizes with AWS SigV4 and IAM only for IamAuth.

A Revision that is receiving traffic at an endpoint cannot be deleted with DeleteWebFunctionRevision.

CloudFront Support

In botocore commit f19f55e01, which first added Lambda Web Functions, changes were also made to the cloudfront model. always-amz-auth was added to the signing behavior of Origin Access Control (OAC).

According to the model's description, CloudFront signs all origin requests with Amazon's authentication header, and if the viewer's request has an Authorization header, it forwards it to the origin. always-amz-auth is exclusively for Lambda-Web origins ("This value is only valid with Lambda-Web origins."). There is also a warning that to forward the viewer's Authorization header, that header must be added to the cache policy. No new operations were added to CloudFront.

IamAuth endpoints are authorized with AWS SigV4 and IAM, and always-amz-auth is the behavior in which CloudFront signs origin requests. From these two points, it appears that a configuration placing an IamAuth endpoint behind CloudFront is anticipated. However, how to specify the origin cannot be determined from the model.

IAM Definitions

The source is codegen/sdk-codegen/aws-models/lambda-web.json in aws-sdk-go-v2. The ARN namespace is lambda, and there are three resource ARN templates.

web-function/{functionName}
web-function/{functionName}/endpoint/{endpointName}
web-function/{functionName}/revision/{revisionId}

There are two condition keys.

  • lambda:Request/WebFunctionAuthType: Restricts access by the authentication method specified in the request. It is attached to CreateWebFunction, CreateWebFunctionEndpoint, and UpdateWebFunctionEndpoint
  • lambda:Resource/WebFunctionAuthType: Restricts access by the authentication method set on the endpoint. It is attached to InvokeWebFunctionEndpoint, UpdateWebFunctionEndpoint, DeleteWebFunctionEndpoint, and GetWebFunctionEndpoint

InvokeWebFunctionEndpoint appears only in the condition key descriptions and is not among the operations in the service model. It appears to be the IAM action for invoking IamAuth endpoints.

CreateWebFunction and CreateWebFunctionRevision have iam:PassRole and lambda:PassNetworkConnector attached as requiredActions. No item corresponding to lambda:PassNetworkConnector can be found in the service model's inputs or outputs.

Things to Check After Public Release

For VPC connectivity, the three information sources are not consistent in how they treat it.

  • The help for aws lambda-web deploy (DESCRIPTION in args.py) directs you to connect to a VPC with the individual API commands. The original text is "such as weighted revision routing or connecting a Web Function to a VPC, use the aws lambda-web commands for specific API operations"
  • The service model has no terms corresponding to "vpc," "subnet," "securitygroup," or "networkconnector"
  • The IAM definition has lambda:PassNetworkConnector

Other items that could not be confirmed from the public source are as follows.

  • Actual quota values. GetWebAccountSettings returns the quotas maxTotalArmVCpus, maxTotalRateLimit, maxRevisionsPerFunction, and maxEndpointsPerFunction, along with the usage functionCount, but the values are not in the model
  • The list of supported runtimes. In the model, runtime is a free-form string, and the CLI's defaults and entry resolution assume Node.js
  • Pricing
  • Cross-checking against official documentation. This covers the IAM Service Authorization Reference and the execution model descriptions (port 3000, zero scaling, streaming, 502)

Summary

As far as can be read from the public source, Lambda Web Functions is a mechanism that runs a Node.js HTTP server listening on a port without handlers or adapters, and with the single command aws lambda-web deploy creates everything from the S3 bucket, execution role, and function through to the endpoint.

CloudFront OAC has also gained always-amz-auth, which is exclusively for Lambda-Web origins.

Overall, it seems well suited to running a Node.js HTTP server written with a lightweight framework in a serverless way.

However, according to the botocore note, the API is experimental and not yet available to external customers. The VPC connectivity specification and pricing are also unknown at this point, but I look forward to the official release.

Share this article

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