AWS.Lambda reference
AppConfigDeploymentEventSource
Section titled “AppConfigDeploymentEventSource”Source:
src/AWS/Lambda/AppConfigDeploymentEventSource.ts
Lambda runtime implementation for AWS.AppConfig.consumeDeploymentEvents(...).
This layer does two things:
- At deploy time it provisions an AppConfig
Extensionwhose actions invoke the current Lambda function at the subscribed deployment action points, the IAM role AppConfig assumes to perform the invocation, and anExtensionAssociationattaching the extension to the target application or environment. - At runtime it narrows incoming invocations to AppConfig deployment
notifications for the bound target and forwards them into the supplied
handler as a typed
DeploymentEventRecordstream.
AppConfigDeploymentEventSource: Consuming Deployment Events
Section titled “AppConfigDeploymentEventSource: Consuming Deployment Events”yield* AppConfig.consumeDeploymentEvents( env, { events: ["ON_DEPLOYMENT_COMPLETE"] }, (events) => events.pipe( Stream.runForEach((event) => Effect.log(`deployment ${event.DeploymentNumber} completed`), ), ),);BucketEventSource
Section titled “BucketEventSource”Source:
src/AWS/Lambda/BucketEventSource.ts
Connects an S3 bucket notification stream to the current Lambda function.
This layer listens for bucket notifications routed through the Lambda runtime
and exposes them as an Effect.Stream, while the companion policy configures
the invoke permission and bucket notification binding during deployment.
BucketEventSource: Wiring Events
Section titled “BucketEventSource: Wiring Events”yield* AWS.Lambda.BucketEventSource( bucket, { events: ["s3:ObjectCreated:*"] }, (events) => Stream.runForEach(events, (event) => Effect.log(event.key)),);CreateAuthToken
Section titled “CreateAuthToken”Source:
src/AWS/Lambda/CreateAuthToken.ts
Runtime binding for CreateMicrovmAuthToken.
Bind it to a MicrovmImage to get a callable that mints a short-lived
token for a running MicroVM. Send it on the MicroVM endpoint in the
X-aws-proxy-auth header.
CreateAuthToken: Auth Tokens
Section titled “CreateAuthToken: Auth Tokens”const createAuthToken = yield* AWS.Lambda.CreateAuthToken(Sandbox);const { authToken } = yield* createAuthToken({ microvmIdentifier: vm.microvmId, expirationInMinutes: 5, allowedPorts: [{ port: 5000 }],});CreateShellAuthToken
Section titled “CreateShellAuthToken”Source:
src/AWS/Lambda/CreateShellAuthToken.ts
Runtime binding for CreateMicrovmShellAuthToken.
Bind it to a MicrovmImage to get a callable that mints a short-lived
token for interactive shell access to a running MicroVM (the MicroVM must
have been run with the shell ingress connector attached).
CreateShellAuthToken: Auth Tokens
Section titled “CreateShellAuthToken: Auth Tokens”const createShellAuthToken = yield* AWS.Lambda.CreateShellAuthToken(Sandbox);const { authToken } = yield* createShellAuthToken({ microvmIdentifier: vm.microvmId, expirationInMinutes: 5,});DeleteMicrovmImageVersion
Section titled “DeleteMicrovmImageVersion”Source:
src/AWS/Lambda/DeleteMicrovmImageVersion.ts
Runtime binding for DeleteMicrovmImageVersion.
Bind it to a MicrovmImage to delete a specific image version (the
imageIdentifier is injected). Idempotent.
DeleteMicrovmImageVersion: Image Versions
Section titled “DeleteMicrovmImageVersion: Image Versions”DurableFunction
Section titled “DurableFunction”Source:
src/AWS/Lambda/DurableFunction.ts
An AWS Lambda Durable Function — a code-first, replay-based orchestrator
that IS a durable Lambda Function. AWS.Lambda.DurableFunction is a
wrapper of Function: it owns the underlying Lambda function,
configures its DurableConfig at CreateFunction (durability is a
create-time property — a DurableFunction is always durable), registers the
durable-execution listener on the owned entrypoint, self-binds the
checkpoint-protocol IAM (lambda:CheckpointDurableExecution,
lambda:GetDurableExecutionState) onto the execution role, and vendors the
open-source @aws/durable-execution-sdk-js into the artifact (install it
in your project: npm i @aws/durable-execution-sdk-js).
Executions progress by checkpoint + replay: a Durable.sleep or
Durable.waitForCallback suspends the execution with zero compute billed
until Lambda re-invokes the same function version to resume, and completed
Durable.steps replay from the checkpoint log without re-executing.
Every invocation of a durable function arrives as the durable-execution
envelope, so a DurableFunction has no HTTP surface (functionUrl is disabled) —
it does one thing: run durable orchestrations. Reusing a logical id
between a plain Function and a DurableFunction replaces the physical
function (DurableConfig cannot be flipped in place).
DurableFunction: Defining a Durable Function
Section titled “DurableFunction: Defining a Durable Function”Class form with steps and a durable sleep
export class OrderFlow extends AWS.Lambda.DurableFunction<OrderFlow>()( "OrderFlow", { main: import.meta.url, executionTimeout: "1 hour", retentionPeriod: "7 days", }, Effect.gen(function* () { // init: resolve typed binding clients (IAM lands on this function's role) const putItem = yield* AWS.DynamoDB.PutItem(table);
return Effect.fn(function* (input: { orderId: string }) { const reserved = yield* AWS.Lambda.Durable.step( "reserve", putItem({ Item: { pk: { S: input.orderId } } }).pipe(Effect.orDie), { retry: { limit: 3, delay: "5 seconds" } }, ); yield* AWS.Lambda.Durable.sleep("cooldown", "10 minutes"); return { orderId: input.orderId, reserved }; }); }),) {}Tag + default export (entrypoint form)
// order-flow.ts — `main` points at this moduleexport class OrderFlow extends AWS.Lambda.DurableFunction<OrderFlow>()( "OrderFlow",) {}
export default OrderFlow.make( { main: import.meta.url, executionTimeout: "1 hour" }, Effect.gen(function* () { return Effect.fn(function* (input: { orderId: string }) { return yield* AWS.Lambda.Durable.step("work", doWork(input)); }); }),);Inline effect form
const flow = yield* AWS.Lambda.DurableFunction( "OrderFlow", { main: "./src/order-flow.ts" }, Effect.gen(function* () { return Effect.fn(function* (input: { orderId: string }) { return yield* AWS.Lambda.Durable.step("work", doWork(input)); }); }),);DurableFunction: Starting and Monitoring Executions
Section titled “DurableFunction: Starting and Monitoring Executions”Starting an execution
const orders = yield* OrderFlow;const ref = yield* orders.start({ name: "order-123", // idempotent start params: { orderId: "123" }, qualifier: "live",});Publish and promote for production
const orders = yield* OrderFlow;const version = yield* AWS.Lambda.Version("OrderFlowVersion", { function: orders.function,});yield* AWS.Lambda.Alias("OrderFlowLive", { version, aliasName: "live",});
const ref = yield* orders.start({ name: "order-123", params: { orderId: "123" }, qualifier: "live",});Checking status
const execution = yield* orders.get(ref.executionArn!);// execution.Status: "RUNNING" | "SUCCEEDED" | "FAILED" | ...DurableFunction: External Callbacks
Section titled “DurableFunction: External Callbacks”const approval = yield* AWS.Lambda.Durable.waitForCallback<{ ok: boolean }>( "approve", (callbackId) => storeCallbackId(callbackId), { timeout: "1 day" },);EventSource
Section titled “EventSource”Source:
src/AWS/Lambda/EventBridgeEventSource.ts
Lambda runtime implementation for AWS.EventBridge.consumeBusEvents(...).
This layer does two things:
- It delegates to
EventSourcePolicyso deployment creates an EventBridge rule targeting the current Lambda function. - At runtime it filters incoming Lambda events against the original event
pattern and forwards matching events into the supplied
Stream.
EventSource: Subscribing To The Default Bus
Section titled “EventSource: Subscribing To The Default Bus”yield* AWS.EventBridge.consumeBusEvents( { source: ["app.user"], "detail-type": ["UserCreated"], }, (events) => Stream.runForEach(events, (event) => Effect.log(`new user: ${event.detail.userId}`), ),);EventSource: Subscribing To A Custom Bus
Section titled “EventSource: Subscribing To A Custom Bus”const bus = yield* AWS.EventBridge.EventBus("OrdersBus", { name: "orders",});
yield* AWS.EventBridge.consumeBusEvents( bus, { source: ["app.orders"], "detail-type": ["OrderPaid"], }, (events) => Stream.runForEach(events, (event) => Effect.log(`paid order: ${event.detail.orderId}`), ),);EventSource: Explicit Route Names
Section titled “EventSource: Explicit Route Names”yield* AWS.EventBridge.consumeBusEvents( "InvoiceEvents", { source: ["app.billing"], "detail-type": ["InvoiceIssued"], }, { description: "Deliver invoice events into this Lambda function", }, (events) => Stream.runForEach(events, (event) => Effect.log(`invoice: ${event.detail.invoiceId}`), ),);EventSource: Processing Typed Details
Section titled “EventSource: Processing Typed Details”type UserCreated = { userId: string; email: string;};
yield* AWS.EventBridge.consumeBusEvents( { source: ["app.user"], "detail-type": ["UserCreated"], }, (events) => Stream.runForEach( events as Stream.Stream<AWS.EventBridge.EventRecord<UserCreated>>, (event) => Effect.log(`welcome ${event.detail.email}`), ),);EventSourceMapping
Section titled “EventSourceMapping”Source:
src/AWS/Lambda/EventSourceMapping.ts
Connects an event source — an SQS queue, Kinesis stream, DynamoDB stream, Amazon MQ broker, or Kafka topic — to a Lambda function so that records are polled from the source and delivered to the function in batches.
Most stacks create mappings indirectly through the higher-level event-source
helpers (SQS.consumeQueueMessages(queue, ...),
Kinesis.consumeStreamRecords(stream, ...), DynamoDB.consumeTableChanges(table, ...)),
which wire up the matching IAM permissions automatically. Use this resource
directly when you need full control over batching, starting position, retry
behavior, or filtering.
EventSourceMapping: Polling an SQS Queue
Section titled “EventSourceMapping: Polling an SQS Queue”SQS is the simplest source: no startingPosition is needed because there is
no stream cursor. Lambda long-polls the queue and invokes the function with
up to batchSize messages, and functionName plus eventSourceArn are the
only required props.
import * as AWS from "alchemy/AWS";
const queue = yield* AWS.SQS.Queue("Jobs", {});const worker = yield* AWS.Lambda.Function("Worker", { main: "./src/worker.ts",});
const mapping = yield* AWS.Lambda.EventSourceMapping("JobsToWorker", { functionName: worker.functionName, eventSourceArn: queue.queueArn, batchSize: 10, maximumBatchingWindow: "5 seconds",});This delivers up to 10 messages per invocation, waiting up to 5 seconds to fill a batch before invoking. Increasing the batching window trades latency for fewer, larger invocations — useful for amortizing cold starts or downstream write costs on bursty queues.
EventSourceMapping: Streaming from Kinesis & DynamoDB
Section titled “EventSourceMapping: Streaming from Kinesis & DynamoDB”Stream sources (Kinesis and DynamoDB Streams) deliver records in shard order
and therefore require a startingPosition that tells Lambda where in the
shard to begin reading. These sources also unlock the stream-only tuning
knobs covered in the next sections.
Process a Kinesis stream from the latest records
import * as AWS from "alchemy/AWS";
const stream = yield* AWS.Kinesis.Stream("Events", {});const consumer = yield* AWS.Lambda.Function("Consumer", { main: "./src/consumer.ts",});
const mapping = yield* AWS.Lambda.EventSourceMapping("EventsToConsumer", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, startingPosition: "LATEST", batchSize: 100,});startingPosition: "LATEST" skips any backlog and only processes records
written after the mapping is created — the right choice for live event
pipelines where replaying history would be wasteful or incorrect.
Replay a DynamoDB stream from the beginning
import * as AWS from "alchemy/AWS";
const table = yield* AWS.DynamoDB.Table("Orders", { partitionKey: { name: "id", type: "S" },});const handler = yield* AWS.Lambda.Function("OrdersStream", { main: "./src/orders.ts",});
const mapping = yield* AWS.Lambda.EventSourceMapping("OrdersToHandler", { functionName: handler.functionName, eventSourceArn: table.latestStreamArn!, startingPosition: "TRIM_HORIZON",});TRIM_HORIZON starts at the oldest record still in the stream, so the
function processes the full available history before catching up to new
writes — use it when every change matters (e.g. building a projection).
Start reading from a specific timestamp
const mapping = yield* AWS.Lambda.EventSourceMapping("EventsFromTime", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, startingPosition: "AT_TIMESTAMP", startingPositionTimestamp: new Date("2026-01-01T00:00:00Z"),});AT_TIMESTAMP (Kinesis only) begins at the first record on or after
startingPositionTimestamp, letting you reprocess a known time range without
replaying the entire stream.
EventSourceMapping: Tuning Throughput
Section titled “EventSourceMapping: Tuning Throughput”For stream sources, throughput is governed by how records are batched and how many batches run in parallel per shard. These knobs let you balance end-to-end latency against invocation count and downstream load.
const mapping = yield* AWS.Lambda.EventSourceMapping("HighThroughput", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, startingPosition: "LATEST", batchSize: 500, maximumBatchingWindow: "10 seconds", parallelizationFactor: 5, tumblingWindow: "30 seconds",});parallelizationFactor runs up to 5 concurrent batches per shard (records
with the same partition key still stay in order), while
tumblingWindow aggregates results across sequential batches for
windowed stream processing. Raising batchSize/maximumBatchingWindow
favors fewer, larger invocations.
EventSourceMapping: Error Handling & Retries
Section titled “EventSourceMapping: Error Handling & Retries”For stream sources a single poison-pill record can block a shard forever. These props bound retries, split failing batches, expire stale records, and route failures elsewhere instead of stalling the stream.
Bisect on error, cap retries, and expire old records
const dlq = yield* AWS.SQS.Queue("StreamFailures", {});
const mapping = yield* AWS.Lambda.EventSourceMapping("ResilientStream", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, startingPosition: "LATEST", bisectBatchOnFunctionError: true, maximumRetryAttempts: 3, maximumRecordAge: "1 hour", destinationConfig: { OnFailure: { Destination: dlq.queueArn }, },});On a function error, bisectBatchOnFunctionError splits the batch in two and
retries each half to isolate the bad record; after maximumRetryAttempts (or
once a record is older than maximumRecordAge) the record is
discarded and its metadata is sent to the destinationConfig.OnFailure
target so it is never silently lost.
Report partial batch failures
const mapping = yield* AWS.Lambda.EventSourceMapping("PartialFailures", { functionName: handler.functionName, eventSourceArn: table.latestStreamArn!, startingPosition: "TRIM_HORIZON", functionResponseTypes: ["ReportBatchItemFailures"],});functionResponseTypes: ["ReportBatchItemFailures"] lets the function return
only the IDs of records it failed to process, so Lambda retries just those
instead of the whole batch — avoiding redundant reprocessing of records that
already succeeded.
EventSourceMapping: Filtering Records
Section titled “EventSourceMapping: Filtering Records”Attach filterCriteria so the function is only invoked for records matching
an event pattern. Filtering happens before invocation, so it cuts both cost
and unnecessary cold starts. Encrypt the patterns with kmsKeyArn when they
contain sensitive values.
const mapping = yield* AWS.Lambda.EventSourceMapping("OrdersOnly", { functionName: worker.functionName, eventSourceArn: queue.queueArn, filterCriteria: { Filters: [{ Pattern: JSON.stringify({ body: { type: ["order"] } }) }], }, kmsKeyArn: "arn:aws:kms:us-east-1:111122223333:key/abcd1234-...",});Each Pattern is a JSON event-pattern string; messages that don’t match are
dropped without invoking the function. The optional kmsKeyArn encrypts the
stored filter criteria with your own KMS key instead of an AWS-managed one.
EventSourceMapping: Enabling & Disabling
Section titled “EventSourceMapping: Enabling & Disabling”The enabled flag controls whether Lambda actively polls the source without
deleting the mapping, so you can pause and resume delivery in place.
const mapping = yield* AWS.Lambda.EventSourceMapping("PausedConsumer", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, startingPosition: "LATEST", enabled: false,});With enabled: false the mapping exists but pulls no records — flip it back
to true to resume. This is handy for maintenance windows or for staging a
consumer before turning on traffic.
EventSourceMapping: Scaling & Provisioned Pollers
Section titled “EventSourceMapping: Scaling & Provisioned Pollers”Cap concurrency for SQS sources with scalingConfig, or reserve dedicated
polling capacity (for Kafka/MSK and SQS) with provisionedPollerConfig to
keep latency predictable under load.
const mapping = yield* AWS.Lambda.EventSourceMapping("BoundedConsumer", { functionName: worker.functionName, eventSourceArn: queue.queueArn, scalingConfig: { MaximumConcurrency: 10 }, provisionedPollerConfig: { MinimumPollers: 1, MaximumPollers: 20, },});scalingConfig.MaximumConcurrency caps how many function instances Lambda
runs for this queue (protecting downstream systems), while
provisionedPollerConfig keeps a pool of dedicated event pollers warm so
throughput doesn’t lag behind sudden spikes.
EventSourceMapping: Kafka, MQ & DocumentDB Sources
Section titled “EventSourceMapping: Kafka, MQ & DocumentDB Sources”Beyond AWS-native streams, an event source mapping can poll Amazon MSK,
self-managed Apache Kafka, Amazon MQ brokers, and Amazon DocumentDB change
streams. These sources use topics/queues to select what to consume,
sourceAccessConfigurations for VPC and authentication wiring, and
source-specific config props.
Consume a self-managed Kafka topic
const mapping = yield* AWS.Lambda.EventSourceMapping("KafkaConsumer", { functionName: consumer.functionName, eventSourceArn: stream.streamArn, topics: ["orders"], selfManagedEventSource: { Endpoints: { KAFKA_BOOTSTRAP_SERVERS: ["broker1:9092", "broker2:9092"] }, }, selfManagedKafkaEventSourceConfig: { ConsumerGroupId: "orders-consumer" }, sourceAccessConfigurations: [ { Type: "SASL_SCRAM_512_AUTH", URI: "arn:aws:secretsmanager:...:secret:kafka" }, ], loggingConfig: { LogFormat: "JSON" },});topics names the Kafka topic(s) to read; selfManagedEventSource.Endpoints
points at the brokers; sourceAccessConfigurations supplies the SASL/VPC
credentials; and selfManagedKafkaEventSourceConfig.ConsumerGroupId pins the
consumer group. For Amazon MSK use amazonManagedKafkaEventSourceConfig
instead.
Consume an Amazon MQ queue and a DocumentDB change stream
const mqMapping = yield* AWS.Lambda.EventSourceMapping("MqConsumer", { functionName: worker.functionName, eventSourceArn: stream.streamArn, queues: ["orders-queue"], sourceAccessConfigurations: [ { Type: "BASIC_AUTH", URI: "arn:aws:secretsmanager:...:secret:mq" }, ],});
const docDbMapping = yield* AWS.Lambda.EventSourceMapping("DocDbConsumer", { functionName: worker.functionName, eventSourceArn: stream.streamArn, documentDBEventSourceConfig: { DatabaseName: "shop", CollectionName: "orders", FullDocument: "UpdateLookup", },});For Amazon MQ, queues names the broker destination to consume and
sourceAccessConfigurations carries the broker credentials; for DocumentDB,
documentDBEventSourceConfig selects the database/collection and whether full
documents are delivered on updates.
EventSourceMapping: Metrics & Tags
Section titled “EventSourceMapping: Metrics & Tags”Opt into per-mapping CloudWatch metrics with metricsConfig and brand the
mapping with your own tags (Alchemy also applies its internal ownership
tags automatically).
const mapping = yield* AWS.Lambda.EventSourceMapping("ObservedConsumer", { functionName: worker.functionName, eventSourceArn: queue.queueArn, metricsConfig: { Metrics: ["EventCount"] }, tags: { team: "payments", env: "prod" },});metricsConfig.Metrics turns on the named CloudWatch metrics (e.g.
EventCount) for this mapping, and tags attaches arbitrary key/value pairs
for cost allocation and discovery.
Function
Section titled “Function”Source:
src/AWS/Lambda/Function.ts
An AWS Lambda host resource that combines code bundling, IAM role provisioning, and runtime binding collection.
Function is the canonical runtime host for AWS. It can either bundle a
TypeScript entry module into a zip artifact or build a user-authored
Dockerfile into a Lambda container image. In both modes Alchemy creates the
execution role and applies bindings; image mode additionally owns the
private ECR repository and Lambda pull policy.
Zip-packaged functions can be defined in two ways:
- Async — plain handler export, no Effect runtime in the bundle.
- Effect — Effect implementation with typed bindings and event sources.
See Effect handlers vs async handlers for plain handler patterns, or the Lambda guide for the full Effect-based approach with bindings, event sources, and sinks.
Function: Async Functions
Section titled “Function: Async Functions”Point main at a file that exports a standard Lambda handler. No
Effect runtime is included in the bundle. Useful when migrating
existing Lambda functions or when you don’t need Effect.
Defining an async Lambda in your stack
import * as AWS from "alchemy/AWS";
const func = yield* AWS.Lambda.Function("ApiFunction", { main: "./src/handler.ts", functionUrl: true,});Function using ARM64
const func = yield* AWS.Lambda.Function("ArmFunction", { main: "./src/handler.ts", architecture: "arm64",});Function with a native package (Sharp)
const func = yield* AWS.Lambda.Function("ImageProcessor", { main: "./src/handler.ts", architecture: "arm64", build: { install: ["sharp"], },});Writing the async handler
export const handler = async (event: any) => { return { statusCode: 200, body: JSON.stringify({ message: "Hello from Lambda!" }), };};Function: Container Image Functions
Section titled “Function: Container Image Functions”Set image instead of main to deploy an existing private ECR image or to
build and publish a local Docker context. Image sources must be literal
because Lambda’s pre-create phase needs the deployable image before normal
Output resolution.
Function: Existing ECR image with runtime overrides
Section titled “Function: Existing ECR image with runtime overrides”const func = yield* AWS.Lambda.Function("Worker", { image: { uri: "123456789012.dkr.ecr.us-east-1.amazonaws.com/worker@sha256:...", command: ["app.handler"], entryPoint: ["/lambda-entrypoint.sh"], workingDirectory: "/var/task", }, architecture: "x86_64",});Tagged URIs are resolved through ECR on each plan. If a tag is repointed to a new digest, Alchemy updates the Lambda function even though the URI string is unchanged. External repositories are never modified or deleted.
Function: Build a Lambda container image
Section titled “Function: Build a Lambda container image”const func = yield* AWS.Lambda.Function("JavaFunction", { image: { context: "./lambda", dockerfile: "Dockerfile", buildArgs: { APP_ENV: "production", }, }, architecture: "arm64", functionUrl: false,});The Dockerfile owns the runtime and handler. Alchemy does not generate a
Node.js adapter or otherwise impose a language. For example,
./lambda/Dockerfile can use AWS’s Java base image:
FROM public.ecr.aws/lambda/java:21COPY target/function.jar ${LAMBDA_TASK_ROOT}/lib/CMD ["com.example.Handler::handleRequest"]Function: Effect Functions
Section titled “Function: Effect Functions”Pass the Effect implementation as the third argument. Bindings attach IAM permissions and environment variables at deploy time, while the runtime execution context collects listeners and exports.
export default class ApiFunction extends AWS.Lambda.Function<ApiFunction>()( "ApiFunction", { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { // init: bind resources const getItem = yield* AWS.DynamoDB.GetItem(table);
return { // runtime: use them fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const url = new URL(request.url); const id = url.searchParams.get("id"); const result = yield* getItem({ Key: { pk: { S: id! } } }); return yield* HttpServerResponse.json(result.Item); }), }; }),) {}Function: Configuration
Section titled “Function: Configuration”Function with URL
const func = yield* AWS.Lambda.Function("ApiFunction", { main: "./src/handler.ts", functionUrl: true,});Function URL with IAM auth
const func = yield* AWS.Lambda.Function("ApiFunction", { main: "./src/handler.ts", functionUrl: { authType: "AWS_IAM", },});Function in a VPC
const func = yield* AWS.Lambda.Function("VpcFunction", { main: "./src/handler.ts", vpc: { subnetIds: ["subnet-abc123", "subnet-def456"], securityGroupIds: ["sg-xyz789"], },});Async invocation retries and failure destination
const func = yield* AWS.Lambda.Function("AsyncFunction", { main: "./src/handler.ts", eventInvokeConfig: { maximumRetryAttempts: 0, maximumEventAge: "1 minute", destinationConfig: { OnFailure: { Destination: queue.queueArn, }, }, },});Function: Bundling & Tree-shaking
Section titled “Function: Bundling & Tree-shaking”main is bundled with rolldown at deploy time. Unused code is
tree-shaken. effect, alchemy, and @distilled.cloud are marked
pure so unused parts prune more aggressively. Your app is not
marked pure.
Mark additional packages as pure
Only list packages with no top-level side effects.
const func = yield* AWS.Lambda.Function("ApiFunction", { main: "./src/handler.ts", build: { pure: { packages: ["my-lib", "@my-scope/*"] }, },});Turn it off
const func = yield* AWS.Lambda.Function("ApiFunction", { main: "./src/handler.ts", build: { pure: false },});Function: EFS File Systems
Section titled “Function: EFS File Systems”Mount an EFS access point into the function’s /mnt/… file system. The
function must be attached to a VPC that can reach an EFS mount target for
the file system.
Mount an EFS access point via props
const accessPoint = yield* AWS.EFS.AccessPoint("FilesAccess", { fileSystemId: fileSystem.fileSystemId, posixUser: { uid: 1000, gid: 1000 },});
const func = yield* AWS.Lambda.Function("FilesFunction", { main: "./src/handler.ts", vpc: { subnetIds, securityGroupIds }, fileSystemConfigs: [ // pass the AccessPoint resource itself (or its ARN via `arn`) { accessPoint, localMountPath: "/mnt/files" }, ],});Mount via the host-agnostic EFS.mount binding
EFS.mount wires the same mount config plus least-privilege IAM through
the binding channel and works on both Lambda and ECS hosts.
export default class FilesFunction extends AWS.Lambda.Function<FilesFunction>()( "FilesFunction", { main: import.meta.url, vpc: { subnetIds, securityGroupIds } }, Effect.gen(function* () { const files = yield* AWS.EFS.mount(accessPoint, { path: "/mnt/files" }); return Effect.fn(function* (event: unknown) { return { mountedAt: files.path }; }); }).pipe(Effect.provide(AWS.EFS.MountLive)),) {}Function: S3 Bindings
Section titled “Function: S3 Bindings”Bind S3 operations in the init phase to give the function IAM permissions and inject the bucket name as an environment variable.
// initconst getObject = yield* S3.GetObject(bucket);const putObject = yield* S3.PutObject(bucket);
return { fetch: Effect.gen(function* () { // runtime yield* putObject({ Key: "hello.txt", Body: "Hello!" }); const obj = yield* getObject({ Key: "hello.txt" }); return HttpServerResponse.text("OK"); }),};Function: DynamoDB Bindings
Section titled “Function: DynamoDB Bindings”Bind DynamoDB operations in the init phase to grant table-scoped IAM permissions.
// initconst getItem = yield* AWS.DynamoDB.GetItem(table);const putItem = yield* AWS.DynamoDB.PutItem(table);
return { fetch: Effect.gen(function* () { // runtime yield* putItem({ Item: { pk: { S: "user#1" }, name: { S: "Alice" } } }); const result = yield* getItem({ Key: { pk: { S: "user#1" } } }); return yield* HttpServerResponse.json(result.Item); }),};Function: SQS Bindings
Section titled “Function: SQS Bindings”Bind SQS operations in the init phase to send messages to a queue.
// initconst sendMessage = yield* SQS.SendMessage(queue);
return { fetch: Effect.gen(function* () { // runtime yield* sendMessage({ MessageBody: JSON.stringify({ orderId: "123" }), }); return HttpServerResponse.text("Queued"); }),};Function: SNS Bindings
Section titled “Function: SNS Bindings”Bind SNS operations in the init phase to publish messages to a topic.
// initconst publish = yield* AWS.SNS.Publish(topic);
return { fetch: Effect.gen(function* () { // runtime yield* publish({ Message: JSON.stringify({ event: "order.created" }), Subject: "OrderCreated", }); return HttpServerResponse.text("Published"); }),};Function: Kinesis Bindings
Section titled “Function: Kinesis Bindings”Bind Kinesis operations in the init phase to put records into a stream.
// initconst putRecord = yield* AWS.Kinesis.PutRecord(stream);
return { fetch: Effect.gen(function* () { // runtime yield* putRecord({ PartitionKey: "order-123", Data: new TextEncoder().encode(JSON.stringify({ orderId: "123" })), }); return HttpServerResponse.text("Sent"); }),};Function: Event Sources
Section titled “Function: Event Sources”Lambda functions can be triggered by event sources like SQS queues, DynamoDB streams, S3 notifications, SNS topics, and Kinesis streams.
Process SQS messages
yield* SQS.consumeQueueMessages(queue, Effect.fn(function* (message) { yield* Effect.log(`Received: ${message.body}`); }),);Process DynamoDB stream changes
yield* AWS.DynamoDB.consumeTableChanges(table, { StreamViewType: "NEW_AND_OLD_IMAGES",}, Effect.fn(function* (record) { yield* Effect.log(`Change: ${record.eventName}`); }),);Process S3 notifications
yield* AWS.S3.consumeBucketEvents(bucket, { events: ["s3:ObjectCreated:*"],}, (stream) => stream.pipe( Stream.runForEach((event) => Effect.log(`New object: ${event.key}`), ), ),);GetAccountSettings
Section titled “GetAccountSettings”Source:
src/AWS/Lambda/GetAccountSettings.ts
Runtime binding for lambda:GetAccountSettings.
An account-level binding — call it with no arguments to get a callable
that reads the region’s Lambda quotas (AccountLimit) and current usage
(AccountUsage). Provide the GetAccountSettingsHttp layer on the
Function to satisfy the binding.
GetAccountSettings: Account Settings
Section titled “GetAccountSettings: Account Settings”const getAccountSettings = yield* AWS.Lambda.GetAccountSettings();
const settings = yield* getAccountSettings();const concurrency = settings.AccountLimit?.ConcurrentExecutions;GetFunction
Section titled “GetFunction”Source:
src/AWS/Lambda/GetFunction.ts
Runtime binding for lambda:GetFunction.
Reads the bound Function’s configuration, code location, and tags —
useful for introspection and operational tooling at runtime. Provide the
GetFunctionHttp layer on the Function to satisfy the binding.
GetFunction: Function Metadata
Section titled “GetFunction: Function Metadata”const getFunction = yield* AWS.Lambda.GetFunction(target);
const response = yield* getFunction();const memory = response.Configuration?.MemorySize;GetMicrovm
Section titled “GetMicrovm”Source:
src/AWS/Lambda/GetMicrovm.ts
Runtime binding for GetMicrovm.
Bind it to a MicrovmImage to get a callable that reads the state,
endpoint, and configuration of a running MicroVM by microvmIdentifier.
GetMicrovm: Inspecting MicroVMs
Section titled “GetMicrovm: Inspecting MicroVMs”const getMicrovm = yield* AWS.Lambda.GetMicrovm(Sandbox);const vm = yield* getMicrovm({ microvmIdentifier: id });GetMicrovmImage
Section titled “GetMicrovmImage”Source:
src/AWS/Lambda/GetMicrovmImage.ts
Runtime binding for GetMicrovmImage.
Bind it to a MicrovmImage to read the image’s state and versions at
runtime (the imageIdentifier is injected).
GetMicrovmImage: Image Reads
Section titled “GetMicrovmImage: Image Reads”const getMicrovmImage = yield* AWS.Lambda.GetMicrovmImage(Sandbox);const image = yield* getMicrovmImage({});GetMicrovmImageBuild
Section titled “GetMicrovmImageBuild”Source:
src/AWS/Lambda/GetMicrovmImageBuild.ts
Runtime binding for GetMicrovmImageBuild.
Bind it to a MicrovmImage to read a per-architecture build’s state and
snapshot info (the imageIdentifier is injected).
GetMicrovmImageBuild: Image Builds
Section titled “GetMicrovmImageBuild: Image Builds”GetMicrovmImageVersion
Section titled “GetMicrovmImageVersion”Source:
src/AWS/Lambda/GetMicrovmImageVersion.ts
Runtime binding for GetMicrovmImageVersion.
Bind it to a MicrovmImage to read the configuration and state of a
specific image version (the imageIdentifier is injected).
GetMicrovmImageVersion: Image Reads
Section titled “GetMicrovmImageVersion: Image Reads”InvokeWithResponseStream
Section titled “InvokeWithResponseStream”Source:
src/AWS/Lambda/InvokeWithResponseStream.ts
Runtime binding for lambda:InvokeFunction over the response-streaming
API. Invokes the bound Function and returns the streaming
response — EventStream yields PayloadChunk events followed by a final
InvokeComplete event.
Provide the InvokeWithResponseStreamHttp layer on the Function to
satisfy the binding.
InvokeWithResponseStream: Invoking Functions
Section titled “InvokeWithResponseStream: Invoking Functions”const invokeStream = yield* AWS.Lambda.InvokeWithResponseStream(target);
const response = yield* invokeStream({ Payload: new TextEncoder().encode(JSON.stringify({ prompt: "hi" })),});const chunks = yield* Stream.runCollect(response.EventStream!);LayerVersion
Section titled “LayerVersion”Source:
src/AWS/Lambda/LayerVersion.ts
A version of a Lambda layer — a zip archive of libraries, a custom runtime,
or other dependencies that Lambda extracts into /opt alongside your
function code.
Layer versions are immutable, so changing the content or any publish
setting publishes a new version under the same layer and retires the one
it supersedes. layerVersionArn and version therefore change on update;
layerName and layerArn stay put.
LayerVersion: Publishing a Layer
Section titled “LayerVersion: Publishing a Layer”Package a Local Directory
// ./layers/deps contains nodejs/node_modules/...const deps = yield* LayerVersion("Deps", { path: "./layers/deps", compatibleRuntimes: ["nodejs22.x"],});Publish an Existing Archive
const layer = yield* LayerVersion("Ffmpeg", { path: "./dist/ffmpeg-layer.zip", description: "static ffmpeg build", compatibleArchitectures: ["arm64"],});Publish From S3
const layer = yield* LayerVersion("BigLayer", { s3: { bucket, key: "layers/big-layer.zip", },});LayerVersion: Attaching to a Function
Section titled “LayerVersion: Attaching to a Function”const fn = yield* Function("Handler", { main: import.meta.resolve("./handler.ts"), layers: [deps],});ListFunctions
Section titled “ListFunctions”Source:
src/AWS/Lambda/ListFunctions.ts
Runtime binding for lambda:ListFunctions.
An account-level binding — call it with no arguments to get a callable
that lists function configurations in the region. Provide the
ListFunctionsHttp layer on the Function to satisfy the binding.
ListFunctions: Function Metadata
Section titled “ListFunctions: Function Metadata”const listFunctions = yield* AWS.Lambda.ListFunctions();
const response = yield* listFunctions({ MaxItems: 50 });const names = response.Functions?.map((f) => f.FunctionName);ListManagedMicrovmImages
Section titled “ListManagedMicrovmImages”Source:
src/AWS/Lambda/ListManagedMicrovmImages.ts
Runtime binding for ListManagedMicrovmImages (account-scoped).
Lists the AWS-managed base MicroVM images available for use as
baseImage. Bind with no resource: yield* AWS.Lambda.ListManagedMicrovmImages().
ListManagedMicrovmImages: Managed Base Images
Section titled “ListManagedMicrovmImages: Managed Base Images”ListManagedMicrovmImageVersions
Section titled “ListManagedMicrovmImageVersions”Source:
src/AWS/Lambda/ListManagedMicrovmImageVersions.ts
Runtime binding for ListManagedMicrovmImageVersions (account-scoped).
Lists versions of an AWS-managed base MicroVM image. Bind with no resource:
yield* AWS.Lambda.ListManagedMicrovmImageVersions().
ListManagedMicrovmImageVersions: Managed Base Images
Section titled “ListManagedMicrovmImageVersions: Managed Base Images”ListMicrovmImageBuilds
Section titled “ListMicrovmImageBuilds”Source:
src/AWS/Lambda/ListMicrovmImageBuilds.ts
Runtime binding for ListMicrovmImageBuilds.
Bind it to a MicrovmImage to list builds for an image version,
optionally filtered by architecture/chipset (the imageIdentifier is
injected).
ListMicrovmImageBuilds: Image Builds
Section titled “ListMicrovmImageBuilds: Image Builds”ListMicrovmImageVersions
Section titled “ListMicrovmImageVersions”Source:
src/AWS/Lambda/ListMicrovmImageVersions.ts
Runtime binding for ListMicrovmImageVersions.
Bind it to a MicrovmImage to list the image’s versions (the
imageIdentifier is injected).
ListMicrovmImageVersions: Image Reads
Section titled “ListMicrovmImageVersions: Image Reads”ListMicrovms
Section titled “ListMicrovms”Source:
src/AWS/Lambda/ListMicrovms.ts
Runtime binding for ListMicrovms.
Bind it to a MicrovmImage to get a callable that lists the MicroVMs
launched from that image (the imageIdentifier filter is injected).
ListMicrovms: Inspecting MicroVMs
Section titled “ListMicrovms: Inspecting MicroVMs”const listMicrovms = yield* AWS.Lambda.ListMicrovms(Sandbox);const { items } = yield* listMicrovms({});LogGroupEventSource
Section titled “LogGroupEventSource”Source:
src/AWS/Lambda/LogGroupEventSource.ts
Lambda runtime implementation for AWS.Logs.consumeLogEvents(...).
This layer does two things:
- At deploy time it creates the backing
AWS.Logs.SubscriptionFiltertargeting the current Lambda function plus thelambda:InvokeFunctionpermission forlogs.amazonaws.com. - At runtime it decodes the gzipped/base64
awslogs.datapayload of incoming invocations and forwards each log event into the supplied handler as a typedLogEventRecordstream.
LogGroupEventSource: Consuming Log Events
Section titled “LogGroupEventSource: Consuming Log Events”yield* AWS.Logs.consumeLogEvents( logGroup, { filterPattern: "?ERROR ?Error" }, (events) => Stream.runForEach(events, (event) => Effect.log(`${event.logStream}: ${event.message}`), ),);MicrovmImage
Section titled “MicrovmImage”Source:
src/AWS/Lambda/MicrovmImage.ts
A Lambda MicroVM image — a Firecracker snapshot that boots a fully
initialized application in milliseconds. The model is image-then-launch:
you create an image once (this resource), then launch isolated, stateful
MicroVM instances from it at runtime (one per end-user/session) with the
RunMicrovm binding from a Lambda Function.
MicrovmImage: How the build works
Section titled “MicrovmImage: How the build works”The build runs server-side on AWS — there is no local Docker. You supply
a code artifact (a zip of a Dockerfile + your code) and a base image
(baseImage); AWS runs your Dockerfile on top of the base, initializes
the app, and takes a Firecracker snapshot. The build is asynchronous: the
provider uploads the artifact, calls CreateMicrovmImage/UpdateMicrovmImage,
and polls until the image reaches CREATED/UPDATED (or surfaces the build
failure). Build logs stream to CloudWatch at /aws/lambda/microvms/<name>.
Alchemy produces the code artifact for you in three ways, selected by which
prop you set (main → context → codeArtifact.uri):
- Effectful (
main): write the in-VM HTTP server in TypeScript as an Effect. Alchemy bundles it (with its capability bindings), generates a Dockerfile on the MicroVM base, zips both, and uploads to the Assets bucket. - External (
context/dockerfile): bring your own Dockerfile + build context (any language). Alchemy zips the directory and uploads it. - Prebuilt (
codeArtifact.uri): point at an existing S3 zip or ECR image URI; nothing is built or uploaded.
Re-deploys only trigger a new build when the artifact’s content hash or a build-affecting prop changes; otherwise the image is left untouched.
MicrovmImage: Prerequisites
Section titled “MicrovmImage: Prerequisites”- A build role (
buildRole) Lambda assumes to read the code artifact and write build logs. Pass aRoleinstance and the required permissions are granted automatically — see the example below. - A bootstrapped Assets bucket (
alchemy provider aws bootstrap) for effectful / external modes, which upload the artifact to S3. - The account must be onboarded to the Lambda MicroVM preview.
MicrovmImage: Creating the Build Role
Section titled “MicrovmImage: Creating the Build Role”Pass a bare Role as buildRole and the MicroVM image grants
everything it needs via a binding: the trust policy (so Lambda can assume it)
plus the S3 (Assets bucket) and CloudWatch-logs permissions (folded into an
alchemy-bindings inline policy). You don’t write any policy yourself.
const buildRole = yield* AWS.IAM.Role("MicrovmBuildRole", {});
// Pass the role instance; trust + permissions are attached for you.const image = yield* AWS.Lambda.MicrovmImage("Sandbox", { main: import.meta.filename, buildRole,});MicrovmImage: Effectful MicroVMs
Section titled “MicrovmImage: Effectful MicroVMs”Write the in-VM server in TypeScript. Alchemy bundles main and bakes it into
the image; the server listens on port (default 8080), which becomes the
MicroVM endpoint.
In-VM HTTP server (single file)
export default class Sandbox extends AWS.Lambda.MicrovmImage<Sandbox>()( "Sandbox", { main: import.meta.filename, buildRole }, Effect.gen(function* () { return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; return HttpServerResponse.text(`hello from ${request.url}`); }), }; }),) {}With capability bindings and env vars
export default class Sandbox extends AWS.Lambda.MicrovmImage<Sandbox>()( "Sandbox", { main: import.meta.filename, buildRole, runtime: "bun", env: { LOG_LEVEL: "info" }, }, Effect.gen(function* () { // bindings are bundled into the image and resolved at runtime const getObject = yield* AWS.S3.GetObject(bucket); return { fetch: Effect.gen(function* () { const obj = yield* getObject({ key: "data.json" }); return HttpServerResponse.json(yield* obj.json); }), }; }).pipe(Effect.provide(AWS.S3.GetObjectHttp)),) {}Class + .make() (two files, for a Lambda orchestrator)
When a Lambda Function imports the image to bind its instance operations, keep
the class (a typed handle) and the .make() runtime in separate files so the
orchestrator’s bundle doesn’t pull in the VM’s runtime deps.
// sandbox.ts — imported by the orchestratorexport class Sandbox extends AWS.Lambda.MicrovmImage<Sandbox>()("Sandbox") {}
// sandbox.live.ts — provided on the Stack; bundled into the image.// Must be the `default` export: the bundler resolves the image entrypoint// from the code artifact's default export.export default Sandbox.make( { main: import.meta.filename, buildRole }, Effect.gen(function* () { return { fetch: Effect.gen(function* () { return HttpServerResponse.text("ok"); }) }; }),);MicrovmImage: Tagged RPC
Section titled “MicrovmImage: Tagged RPC”Beyond (or instead of) a raw fetch handler, an image can expose a typed
RPC Shape as the second type parameter. The in-VM runtime serves those
methods over an /__rpc__/* protocol and falls through to fetch for every
other request, so an image can offer BOTH a typed RPC surface and ordinary
HTTP routes. A caller gets a fully-typed client with connectMicrovm:
value methods yield* as Effects, streaming methods pipe as Streams.
Define a tagged-RPC image (RPC + fetch)
// sandbox.ts — the typed handle imported by the orchestrator Lambdaexport class Sandbox extends AWS.Lambda.MicrovmImage< Sandbox, { hello: (message: string) => Effect.Effect<string> }>()("Sandbox") {}
// sandbox.live.ts — provided on the Stack; bundled into the image (default export)export default Sandbox.make( { main: import.meta.filename, buildRole }, Effect.gen(function* () { return { // RPC method — reached with `connectMicrovm` below hello: (message: string) => Effect.succeed(`hello, ${message}!`), // raw HTTP route — reached with a plain HTTPS request to the endpoint fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const url = new URL(request.url, "http://microvm"); return HttpServerResponse.json({ path: url.pathname }); }), }; }),);Call the RPC method from a Lambda
connectMicrovm builds the typed stub over an HttpClient (provide
FetchHttpClient.layer for the request scope), pointing at the running
MicroVM’s endpoint and authenticating with the authToken headers.
const vm = yield* runMicrovm({});// ...wait until `vm.state` is RUNNING (poll `getMicrovm`)...const { authToken } = yield* createAuthToken({ microvmIdentifier: vm.microvmId, expirationInMinutes: 5, allowedPorts: [{ port: 8080 }], // the in-VM server's port});
const sandbox = yield* AWS.Lambda.connectMicrovm(Sandbox, { endpoint: vm.endpoint, authToken,});const reply = yield* sandbox.hello("world"); // "hello, world!"Call the same MicroVM’s fetch route directly
For the raw HTTP path, send the auth token as request headers via
microvmAuthHeaders.
const client = yield* HttpClient.HttpClient;const res = yield* client.get(`https://${vm.endpoint}/echo?message=hi`, { headers: AWS.Lambda.microvmAuthHeaders(authToken),});const body = yield* res.json;MicrovmImage: Bundling & Tree-shaking
Section titled “MicrovmImage: Bundling & Tree-shaking”main is bundled with rolldown at deploy time. Unused code is
tree-shaken. effect, alchemy, and @distilled.cloud are marked
pure so unused parts prune more aggressively. Your app is not
marked pure.
Mark additional packages as pure
Only list packages with no top-level side effects.
{ main: import.meta.url, build: { pure: { packages: ["my-lib", "@my-scope/*"] }, },}Turn it off
{ main: import.meta.url, build: { pure: false },}MicrovmImage: External Images (your own Dockerfile)
Section titled “MicrovmImage: External Images (your own Dockerfile)”Bring a build context directory containing a Dockerfile (any language).
Alchemy zips and uploads it; AWS runs your Dockerfile. Your Dockerfile should
build on a MicroVM-compatible base (e.g.
FROM public.ecr.aws/lambda/microvms:al2023-minimal).
Flask app from a Dockerfile
const image = yield* AWS.Lambda.MicrovmImage("Flask", { context: `${import.meta.dirname}/app`, // dir with Dockerfile + app.py buildRole,});Custom Dockerfile path within the context
const image = yield* AWS.Lambda.MicrovmImage("Worker", { context: `${import.meta.dirname}/app`, dockerfile: "docker/worker.Dockerfile", // relative to `context` buildRole,});MicrovmImage: Prebuilt Artifacts
Section titled “MicrovmImage: Prebuilt Artifacts”Skip the build entirely and point at an artifact you already produced.
const image = yield* AWS.Lambda.MicrovmImage("Prebuilt", { codeArtifact: { uri: "s3://my-bucket/app.zip" }, // or an ECR image URI buildRole,});MicrovmImage: Sizing and Base Image
Section titled “MicrovmImage: Sizing and Base Image”baseImage defaults to the latest AWS-managed al2023 base (discovered
via listManagedMicrovmImages). Override it, and tune CPU/memory, explicitly.
const image = yield* AWS.Lambda.MicrovmImage("Sized", { main: import.meta.filename, buildRole, baseImage: "arn:aws:lambda:us-east-1:aws:microvm-image:al2023-1", cpuConfigurations: [{ architecture: "ARM_64" }], resources: [{ minimumMemoryInMiB: 2048 }],});MicrovmImage: Logging
Section titled “MicrovmImage: Logging”const image = yield* AWS.Lambda.MicrovmImage("Logged", { main: import.meta.filename, buildRole, logging: { cloudWatch: { logGroup: "/aws/microvm/my-app" } }, // or disable: logging: { disabled: {} }});MicrovmImage: VPC Egress
Section titled “MicrovmImage: VPC Egress”Give the MicroVM a managed egress path into your VPC with a
NetworkConnector (reference it by ARN).
const egress = yield* AWS.Lambda.NetworkConnector("Egress", { subnetIds: [subnet.subnetId], securityGroupIds: [sg.groupId], operatorRole: operatorRole.roleArn,});
const image = yield* AWS.Lambda.MicrovmImage("Connected", { main: import.meta.filename, buildRole, egressNetworkConnectors: [egress.networkConnectorArn],});MicrovmImage: Launching MicroVMs
Section titled “MicrovmImage: Launching MicroVMs”The image is just the template. Launch and drive instances from a Lambda
Function using the per-operation bindings (RunMicrovm,
GetMicrovm, CreateAuthToken, TerminateMicrovm, …).
Each binding’s IAM policy is scoped to this image automatically.
Always terminate the MicroVM you launched — wrap the work in
Effect.ensuring so a failure (or a client retry) never leaks a running
MicroVM against your account’s memory quota. Give the Function a generous
timeout since it waits for the MicroVM to reach RUNNING in-line.
export default class Api extends AWS.Lambda.Function<Api>()( "Api", { main: import.meta.filename, functionUrl: true, timeout: Duration.seconds(120) }, Effect.gen(function* () { const runMicrovm = yield* AWS.Lambda.RunMicrovm(Sandbox); const getMicrovm = yield* AWS.Lambda.GetMicrovm(Sandbox); const createAuthToken = yield* AWS.Lambda.CreateAuthToken(Sandbox); const terminateMicrovm = yield* AWS.Lambda.TerminateMicrovm(Sandbox); return { fetch: Effect.gen(function* () { const vm = yield* runMicrovm({ idlePolicy: { maxIdleDurationSeconds: 900, suspendedDurationSeconds: 300, autoResumeEnabled: true, }, }); return yield* Effect.gen(function* () { // wait until the MicroVM is RUNNING before connecting yield* getMicrovm({ microvmIdentifier: vm.microvmId }).pipe( Effect.flatMap((m) => m.state === "RUNNING" ? Effect.void : Effect.fail(new Error(`microvm ${m.state}`)), ), Effect.retry({ schedule: Schedule.spaced("2 seconds"), times: 30 }), ); const { authToken } = yield* createAuthToken({ microvmIdentifier: vm.microvmId, expirationInMinutes: 5, allowedPorts: [{ port: 8080 }], }); const sandbox = yield* AWS.Lambda.connectMicrovm(Sandbox, { endpoint: vm.endpoint, authToken, }); const reply = yield* sandbox.hello("world"); return yield* HttpServerResponse.json({ reply }); }).pipe( // terminate on success OR failure — never leak a running MicroVM Effect.ensuring( terminateMicrovm({ microvmIdentifier: vm.microvmId }).pipe( Effect.ignore, ), ), // the in-VM endpoint calls need an HttpClient for this scope Effect.provide(FetchHttpClient.layer), ); }), }; }).pipe( Effect.provide( Layer.mergeAll( AWS.Lambda.RunMicrovmHttp, AWS.Lambda.GetMicrovmHttp, AWS.Lambda.CreateAuthTokenHttp, AWS.Lambda.TerminateMicrovmHttp, ), ), ),) {}NetworkConnector
Section titled “NetworkConnector”Source:
src/AWS/Lambda/NetworkConnector.ts
A Lambda network connector that gives Lambda compute resources — notably
MicrovmImage MicroVMs — a managed egress path into your VPC. The
connector provisions elastic network interfaces (ENIs) in the subnets you
specify so workloads can reach private resources such as databases, caches,
and internal APIs.
Creation is asynchronous: the connector starts in PENDING while ENIs are
provisioned (this can take several minutes) and the provider waits until it
reaches ACTIVE. The connector name is immutable, so renaming it replaces the
connector; the VPC configuration and operator role can be updated in place.
NetworkConnector: Creating a Network Connector
Section titled “NetworkConnector: Creating a Network Connector”const connector = yield* AWS.Lambda.NetworkConnector("Egress", { subnetIds: [subnetA.subnetId, subnetB.subnetId], securityGroupIds: [securityGroup.groupId], operatorRole: role.roleArn,});NetworkConnector: Dual-Stack Networking
Section titled “NetworkConnector: Dual-Stack Networking”const connector = yield* AWS.Lambda.NetworkConnector("DualStack", { subnetIds: [subnet.subnetId], securityGroupIds: [securityGroup.groupId], networkProtocol: "DualStack",});NetworkConnector: Using a Connector with MicroVMs
Section titled “NetworkConnector: Using a Connector with MicroVMs”A connector is the producer; a MicrovmImage (or a per-run
RunMicrovm call) is the consumer. Reference it by ARN in
egressNetworkConnectors.
const image = yield* AWS.Lambda.MicrovmImage("Sandbox", { main: import.meta.filename, buildRole, egressNetworkConnectors: [connector.networkConnectorArn],});Permission
Section titled “Permission”Source:
src/AWS/Lambda/Permission.ts
A Lambda permission that grants an AWS service or another account permission to invoke a function.
Permission: Granting Permissions
Section titled “Permission: Granting Permissions”S3 Notification Permission
const perm = yield* Permission("S3Invoke", { action: "lambda:InvokeFunction", functionName: yield* fn.functionArn(), principal: "s3.amazonaws.com", sourceArn: yield* bucket.bucketArn, sourceAccount: (yield* AWSEnvironment.current).accountId,});Cross Account Invoke
const perm = yield* Permission("CrossAccount", { action: "lambda:InvokeFunction", functionName: yield* fn.functionArn(), principal: "123456789012",});Public Function URL
const perm = yield* Permission("PublicUrl", { action: "lambda:InvokeFunctionUrl", functionName: yield* fn.functionArn(), principal: "*", functionUrlAuthType: "NONE",});RestApiEventSource
Section titled “RestApiEventSource”Source:
src/AWS/Lambda/RestApiEventSource.ts
Connects a REST API (v1) route to the current Lambda function.
At deploy time this layer materializes the path Resource chain, the
Method with an AWS_PROXY integration, and the API Gateway invoke
Permission for each registered route — and registers each child as a
RestApiBinding on the API so any Deployment of the same API is
ordered after them. At runtime it dispatches matching REST proxy events
to the registered handler.
RestApiEventSource: Handling REST API routes
Section titled “RestApiEventSource: Handling REST API routes”yield* AWS.ApiGateway.onRestApiRoute( api, { path: "/items", httpMethod: "GET" }, () => Effect.succeed({ statusCode: 200, body: JSON.stringify({ items: [] }), }),);ResumeMicrovm
Section titled “ResumeMicrovm”Source:
src/AWS/Lambda/ResumeMicrovm.ts
Runtime binding for ResumeMicrovm.
Bind it to a MicrovmImage to get a callable that resumes a suspended
MicroVM by microvmIdentifier, restoring it to RUNNING.
ResumeMicrovm: Lifecycle
Section titled “ResumeMicrovm: Lifecycle”const resumeMicrovm = yield* AWS.Lambda.ResumeMicrovm(Sandbox);yield* resumeMicrovm({ microvmIdentifier: id });RoomMessageReviewEventSource
Section titled “RoomMessageReviewEventSource”Source:
src/AWS/Lambda/RoomMessageReviewEventSource.ts
Connects an IVS Chat room’s message review handler to the current Lambda function.
At deploy time this layer injects the function ARN into the room’s
messageReviewHandler through the room’s binding contract and
materializes the lambda:InvokeFunction Permission for
ivschat.amazonaws.com; at runtime it dispatches review invocations
(matched on RoomArn) to the registered handler and returns the verdict
to IVS Chat.
RoomMessageReviewEventSource: Reviewing room messages
Section titled “RoomMessageReviewEventSource: Reviewing room messages”yield* IVSChat.onReviewMessage(room, (event) => Effect.succeed( event.Content.includes("banned-word") ? { ReviewResult: "DENY", Attributes: { Reason: "moderated" } } : undefined, ),);RunMicrovm
Section titled “RunMicrovm”Source:
src/AWS/Lambda/RunMicrovm.ts
Runtime binding for RunMicrovm.
Bind it to a MicrovmImage inside a Lambda Function to get a callable
that launches a MicroVM from that image (the imageIdentifier is injected).
The response carries the MicroVM endpoint; connect to it with an
X-aws-proxy-auth token from CreateAuthToken.
RunMicrovm: Running MicroVMs
Section titled “RunMicrovm: Running MicroVMs”const runMicrovm = yield* AWS.Lambda.RunMicrovm(Sandbox);
const vm = yield* runMicrovm({ idlePolicy: { maxIdleDurationSeconds: 900, suspendedDurationSeconds: 300, autoResumeEnabled: true, },});ScheduleEventSource
Section titled “ScheduleEventSource”Source:
src/AWS/Lambda/ScheduleEventSource.ts
Lambda runtime implementation for AWS.Scheduler.consumeSchedule(...) —
the “cron handler” DX where a Lambda consumes its own EventBridge Scheduler
invocations.
This layer does two things:
- At deploy time it creates the backing
Scheduletargeting the current Lambda function, plus the synthesized execution role that allows EventBridge Scheduler to invoke it. - At runtime it matches incoming Lambda events against the schedule’s
typed envelope (
isScheduleEvent+ the stable route id) and dispatches them to the supplied handler.
ScheduleEventSource: Consuming Scheduled Invocations
Section titled “ScheduleEventSource: Consuming Scheduled Invocations”Run A Handler Every 5 Minutes
yield* AWS.Scheduler.consumeSchedule( AWS.Scheduler.every("5 minutes"), (event) => Effect.log(`fired at ${event.scheduledTime}`),);Nightly Cron With An Explicit Route Id
yield* AWS.Scheduler.consumeSchedule( "NightlyCleanup", AWS.Scheduler.cron("cron(0 3 * * ? *)"), (event) => Effect.log(`cleanup ${event.executionId}`),);SecretRotationEventSource
Section titled “SecretRotationEventSource”Source:
src/AWS/Lambda/SecretRotationEventSource.ts
Lambda runtime implementation for
AWS.SecretsManager.onSecretRotation(...).
This layer does three things at deploy time:
- Grants
secretsmanager.amazonaws.compermission to invoke the current function (scoped to this account viaaws:SourceAccount). - Attaches the rotation-protocol IAM actions for the bound secret
(
DescribeSecret,GetSecretValue,PutSecretValue,UpdateSecretVersionStageon the secret +GetRandomPassword). - Provisions the
RotationScheduleconfiguring the secret’s rotation to invoke this function — threaded through the Permission so Secrets Manager’s invoke-permission validation passes.
At runtime it narrows incoming invocations to rotation events for the bound secret and forwards them to the supplied handler.
SecretRotationEventSource: Rotating Secrets
Section titled “SecretRotationEventSource: Rotating Secrets”yield* SecretsManager.onSecretRotation( secret, { rotationRules: { automaticallyAfter: "30 days" } }, (event) => rotate(event).pipe(Effect.orDie),);SuspendMicrovm
Section titled “SuspendMicrovm”Source:
src/AWS/Lambda/SuspendMicrovm.ts
Runtime binding for SuspendMicrovm.
Bind it to a MicrovmImage to get a callable that suspends a running
MicroVM (snapshotting memory + disk) by microvmIdentifier.
SuspendMicrovm: Lifecycle
Section titled “SuspendMicrovm: Lifecycle”const suspendMicrovm = yield* AWS.Lambda.SuspendMicrovm(Sandbox);yield* suspendMicrovm({ microvmIdentifier: id });TerminateMicrovm
Section titled “TerminateMicrovm”Source:
src/AWS/Lambda/TerminateMicrovm.ts
Runtime binding for TerminateMicrovm.
Bind it to a MicrovmImage to get a callable that terminates a running
MicroVM by microvmIdentifier. Idempotent.
TerminateMicrovm: Lifecycle
Section titled “TerminateMicrovm: Lifecycle”const terminateMicrovm = yield* AWS.Lambda.TerminateMicrovm(Sandbox);yield* terminateMicrovm({ microvmIdentifier: id });UpdateMicrovmImageVersion
Section titled “UpdateMicrovmImageVersion”Source:
src/AWS/Lambda/UpdateMicrovmImageVersion.ts
Runtime binding for UpdateMicrovmImageVersion.
Bind it to a MicrovmImage to update a version’s status (e.g. mark it
ACTIVE/INACTIVE); the imageIdentifier is injected.
UpdateMicrovmImageVersion: Image Versions
Section titled “UpdateMicrovmImageVersion: Image Versions”UserPoolTriggerEventSource
Section titled “UserPoolTriggerEventSource”Source:
src/AWS/Lambda/UserPoolTriggerEventSource.ts
Connects a Cognito user pool Lambda trigger to the current Lambda function.
At deploy time this layer injects the function ARN into the pool’s
LambdaConfig through the pool’s binding contract and materializes the
lambda:InvokeFunction Permission for cognito-idp.amazonaws.com; at
runtime it dispatches matching trigger events (matched on userPoolId +
triggerSource prefix) to the registered handler and returns the
handler’s (mutated) event to Cognito.
UserPoolTriggerEventSource: Handling user pool triggers
Section titled “UserPoolTriggerEventSource: Handling user pool triggers”yield* Cognito.onPreSignUp(pool, (event) => Effect.sync(() => Cognito.autoConfirmUser(event, { verifyEmail: true })),);Version
Section titled “Version”Source:
src/AWS/Lambda/Version.ts
An immutable numbered version of a managed Lambda function.
The provider publishes only after the Function’s code and configuration have settled. Re-applying unchanged code and versioned configuration reuses the existing version. Function-level operational changes, such as reserved concurrency, do not publish a new version.
Versions default to retain on removal. Moving or deleting an alias never
deletes an older version, so in-flight durable executions can continue
replaying against the code that started them. Use destroy() only when the
exact numbered version is safe to remove.
Version: Publishing a Version
Section titled “Version: Publishing a Version”const fn = yield* AWS.Lambda.Function("Handler", { main: import.meta.resolve("./handler.ts"),});const version = yield* AWS.Lambda.Version("HandlerVersion", { function: fn,});Version: Promoting with an Alias
Section titled “Version: Promoting with an Alias”const version = yield* AWS.Lambda.Version("CampaignRunVersion", { function: campaign.function,});const live = yield* AWS.Lambda.Alias("CampaignRunLive", { version, aliasName: "live",});Version: Explicit Deletion
Section titled “Version: Explicit Deletion”import { destroy } from "alchemy/RemovalPolicy";
const disposable = yield* AWS.Lambda.Version("PreviewVersion", { function: fn,}).pipe(destroy());WebSocketEventSource
Section titled “WebSocketEventSource”Source:
src/AWS/Lambda/WebSocketEventSource.ts
Connects a WebSocket API route to the current Lambda function.
At deploy time this layer materializes the AWS_PROXY Integration, the
Route, and the API Gateway invoke Permission for each registered route
key; at runtime it dispatches matching WebSocket proxy events to the
registered handler.
WebSocketEventSource: Handling WebSocket routes
Section titled “WebSocketEventSource: Handling WebSocket routes”const connections = yield* AWS.ApiGatewayV2.ManageConnections(stage);
yield* AWS.ApiGatewayV2.onWebSocketRoute(api, { routeKey: "$connect" }, () => Effect.succeed({ statusCode: 200 }),);yield* AWS.ApiGatewayV2.onWebSocketRoute(api, { routeKey: "$default" }, (event) => connections .postToConnection({ ConnectionId: event.requestContext.connectionId, Data: `echo:${event.body ?? ""}`, }) .pipe( Effect.asVoid, Effect.catchTag("GoneException", () => Effect.void), Effect.orDie, ),);WirelessDestinationEventSource
Section titled “WirelessDestinationEventSource”Source:
src/AWS/Lambda/WirelessDestinationEventSource.ts
Connects an IoT Wireless Destination’s uplink traffic to the
current Lambda function.
At deploy time this layer creates the IoT topic rule named by the
destination’s expression (the destination must use
expressionType: "RuleName") with a Lambda action targeting this
function, and grants iot.amazonaws.com permission to invoke it; at
runtime it dispatches uplink invocations to the registered handler.
WirelessDestinationEventSource: Consuming wireless uplinks
Section titled “WirelessDestinationEventSource: Consuming wireless uplinks”yield* IoTWireless.consumeUplinks(destination, (uplinks) => uplinks.pipe( Stream.runForEach((uplink) => Effect.log(uplink.PayloadData)), Effect.orDie, ),);