Deploy a Serverless Worker on AWS Lambda
This guide walks through deploying a Temporal Worker on AWS Lambda.
Prerequisites
- A Temporal Cloud account or a self-hosted Temporal Service vx.xx.x or later.
- Your Temporal Service frontend must be reachable from the Lambda execution environment. For Temporal Cloud, no additional configuration is needed. For self-hosted deployments on a private network, configure the Lambda function with VPC access to reach the Temporal frontend.
- An AWS account with permissions to create and invoke Lambda functions and create IAM roles.
- The AWS-specific steps in this guide require the
awsCLI installed and configured with your AWS credentials. You may use other tools to perform the steps, such as the AWS Console or the AWS SDKs.
- The Go SDK (
go.temporal.io/sdk)
1. Write the Worker code
Write a Worker that runs inside a Lambda function. The Worker handles the per-invocation lifecycle: connecting to Temporal, polling for tasks, and gracefully shutting down before the invocation deadline.
Use the Go SDK's lambdaworker package.
package main
import (
lambdaworker "go.temporal.io/sdk/contrib/aws/lambdaworker"
"go.temporal.io/sdk/worker"
"go.temporal.io/sdk/workflow"
)
func main() {
lambdaworker.RunWorker(worker.WorkerDeploymentVersion{
DeploymentName: "my-app",
BuildID: "build-1",
}, func(opts *lambdaworker.Options) error {
opts.TaskQueue = "my-task-queue"
opts.RegisterWorkflowWithOptions(MyWorkflow, workflow.RegisterOptions{
VersioningBehavior: workflow.VersioningBehaviorAutoUpgrade,
})
opts.RegisterActivity(MyActivity)
return nil
})
}
Each Workflow must declare a versioning behavior at registration time, either AutoUpgrade or Pinned.
For details on configuration options, Lambda-tuned defaults, and the invocation lifecycle, see Serverless Workers - Go SDK.
2. Deploy the Lambda function
Build your Worker for the Lambda runtime, package it as a zip, and deploy it to AWS Lambda.
i. Build and package
Cross-compile for Lambda's Linux runtime:
GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o bootstrap ./worker
Package the binary into a zip file:
zip function.zip bootstrap
ii. Deploy the Lambda function
aws lambda create-function \
--function-name my-temporal-worker \
--runtime provided.al2023 \
--handler bootstrap \
--role arn:aws:iam::<YOUR_ACCOUNT_ID>:role/my-temporal-worker-execution \
--zip-file fileb://function.zip \
--timeout 600 \
--memory-size 256 \
--environment "Variables={HOME=/tmp,TEMPORAL_ADDRESS=<your-temporal-address>:7233,TEMPORAL_NAMESPACE=<your-namespace>,TEMPORAL_API_KEY=<your-api-key>}"
| Parameter | Description |
|---|---|
--function-name | Name of the Lambda function. |
--runtime | Lambda runtime. Use provided.al2023 for custom Go binaries. |
--handler | Entry point binary name. Must be bootstrap when using the provided.al2023 custom runtime. |
--role | ARN of the Lambda execution role, which grants the function permission to run. Trusted principal must be lambda.amazonaws.com. This is separate from the role Temporal uses to invoke the function in Step 3. |
--zip-file | Path to your packaged deployment zip. |
--timeout | Invocation deadline in seconds. This is the maximum time each Lambda invocation can run before AWS terminates it. Set this high enough for the Worker to start, process Tasks, and shut down gracefully. |
--memory-size | Memory in MB allocated to each invocation. |
HOME | Must be /tmp. |
TEMPORAL_ADDRESS | Temporal frontend address (e.g., <namespace>.<account>.tmprl.cloud:7233). |
TEMPORAL_NAMESPACE | Temporal Namespace. |
TEMPORAL_TASK_QUEUE | Task Queue name. Overrides the value set in code. |
TEMPORAL_TLS_CLIENT_CERT_PATH | Path to the TLS client certificate file for mTLS authentication. |
TEMPORAL_TLS_CLIENT_KEY_PATH | Path to the TLS client key file for mTLS authentication. |
TEMPORAL_API_KEY | API key for API key authentication. |
The lambdaworker package reads environment variables automatically at startup. For the full list, see Client environment configuration.
Sensitive values like TLS keys and API keys should be encrypted at rest. See AWS documentation for options.
To update an existing function with new code:
aws lambda update-function-code \
--function-name my-temporal-worker \
--zip-file fileb://function.zip
3. Configure IAM for Temporal invocation
Temporal needs permission to invoke your Lambda function.
The Temporal server assumes an IAM role in your AWS account to call lambda:InvokeFunction.
The trust policy on the role includes an External ID condition to prevent confused deputy attacks.
Deploy the following CloudFormation template to create the invocation role and its permissions. Download the template.
This template is scoped to Temporal Cloud. Self-hosted configuration guidance is in progress.
| Parameter | Description |
|---|---|
AssumeRoleExternalId | A unique identifier that Temporal Cloud presents when assuming the role. Provided in your Namespace configuration. |
LambdaFunctionARNs | Comma-separated list of Lambda function ARNs that Temporal may invoke. One role can authorize multiple Worker Lambdas. |
RoleName | Base name for the created IAM role. Defaults to Temporal-Cloud-Serverless-Worker. |
CloudFormation template
# CloudFormation template for creating an IAM role that Temporal Cloud can assume to invoke Lambda functions.
AWSTemplateFormatVersion: '2010-09-09'
Description: Creates an IAM role that Temporal Cloud can assume to invoke multiple Lambda functions for Serverless Workers.
Parameters:
AssumeRoleExternalId:
Type: String
Description: The External ID provided by Temporal Cloud
AllowedPattern: '[a-zA-Z0-9_+=,.@-]*'
MinLength: 5
MaxLength: 45
LambdaFunctionARNs:
Type: CommaDelimitedList
Description: >-
Comma-separated list of Lambda function ARNs to invoke
(e.g., arn:aws:lambda:us-west-2:123456789012:function:worker-1,arn:aws:lambda:us-west-2:123456789012:function:worker-2)
RoleName:
Type: String
Default: 'Temporal-Cloud-Serverless-Worker'
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Temporal Cloud Configuration"
Parameters:
- AssumeRoleExternalId
- Label:
default: "Lambda Configuration"
Parameters:
- LambdaFunctionARNs
- RoleName
ParameterLabels:
AssumeRoleExternalId:
default: "External ID (provided by Temporal Cloud)"
LambdaFunctionARNs:
default: "Lambda Function ARNs (comma-separated list)"
RoleName:
default: "IAM Role Name"
Resources:
TemporalCloudServerlessWorker:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${RoleName}-${AWS::StackName}'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
[
arn:aws:iam::902542641901:role/wci-lambda-invoke,
arn:aws:iam::160190466495:role/wci-lambda-invoke,
arn:aws:iam::819232936619:role/wci-lambda-invoke,
arn:aws:iam::829909441867:role/wci-lambda-invoke,
arn:aws:iam::354116250941:role/wci-lambda-invoke
]
Action: sts:AssumeRole
Condition:
StringEquals:
'sts:ExternalId': [!Ref AssumeRoleExternalId]
Description: "The role Temporal Cloud uses to invoke Lambda functions for Serverless Workers"
MaxSessionDuration: 3600 # 1 hour
TemporalCloudLambdaInvokePermissions:
Type: AWS::IAM::Policy
DependsOn: TemporalCloudServerlessWorker
Properties:
PolicyName: 'Temporal-Cloud-Lambda-Invoke-Permissions'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:GetFunction
Resource: !Ref LambdaFunctionARNs
Roles:
- !Sub '${RoleName}-${AWS::StackName}'
Outputs:
RoleARN:
Description: The ARN of the IAM role created for Temporal Cloud
Value: !GetAtt TemporalCloudServerlessWorker.Arn
Export:
Name: !Sub "${AWS::StackName}-RoleARN"
RoleName:
Description: The name of the IAM role
Value: !Ref RoleName
LambdaFunctionARNs:
Description: The Lambda function ARNs that can be invoked
Value: !Join [", ", !Ref LambdaFunctionARNs]
Deploy the template:
aws cloudformation create-stack \
--stack-name <STACK_NAME> \
--template-body file://temporal-cloud-serverless-worker-role.yaml \
--parameters \
ParameterKey=AssumeRoleExternalId,ParameterValue=<EXTERNAL_ID> \
ParameterKey=LambdaFunctionARNs,ParameterValue='"<LAMBDA_FUNCTION_ARN>"' \
--capabilities CAPABILITY_NAMED_IAM \
--region <AWS_REGION>
The stack output RoleARN contains the IAM role ARN to use in your Worker Deployment Version's compute configuration.
4. Create a Worker Deployment Version
Create a Worker Deployment Version with a compute provider that points to your Lambda function.
The compute configuration tells Temporal how to invoke your Worker: the provider type (aws-lambda), the Lambda function ARN, and the IAM role to assume.
The deployment name and build ID must match the values in your Worker code.
You can create the version using the Temporal UI, the Temporal CLI, or programmatically with an SDK.
- Temporal UI
- Temporal CLI
- SDK
- In the Temporal UI, open your Namespace.
- In the left pane, select Workers.
- Click Create Worker Deployment in the upper right corner.
- Under Configuration, enter a Name and Build ID. These must match the
DeploymentNameandBuildIDin your Worker code. - Under Compute, select AWS Lambda and provide:
- Lambda ARN: the ARN of your Lambda function.
- IAM Role ARN: the role ARN from Step 3 (output of the CloudFormation stack).
- External ID: the same value you passed to the CloudFormation template.
- Click Save.
When you create a version through the UI, the version is automatically set as current. Skip to Verify the deployment.
Use the CLI for manual setup, shell scripts, and CI/CD pipelines. When you create a version through the CLI, you must set the version as current as a separate step.
temporal worker deployment create-version \
--namespace <YOUR_NAMESPACE> \
--deployment-name my-app \
--build-id build-1 \
--aws-lambda-function-arn arn:aws:lambda:<REGION>:<ACCOUNT_ID>:function:my-temporal-worker \
--aws-lambda-assume-role-arn arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME> \
--aws-lambda-assume-role-external-id <EXTERNAL_ID>
| Flag | Description |
|---|---|
--deployment-name | Worker Deployment name. Must match DeploymentName in your Worker code. |
--build-id | Worker Deployment Version build ID. Must match BuildID in your Worker code. |
--aws-lambda-function-arn | ARN of the Lambda function Temporal invokes for this version. |
--aws-lambda-assume-role-arn | IAM role Temporal assumes to invoke the function. This is the RoleARN output from the CloudFormation stack in Step 3. |
--aws-lambda-assume-role-external-id | External ID configured in the IAM role trust policy. |
Use the SDK when the deployment registration is part of your application, for example a setup program that provisions infrastructure and registers the version together, or when you need to compute values dynamically. When you create a version through the SDK, you must set the version as current as a separate step.
// Create the worker deployment
client.CreateWorkerDeployment(ctx, &workflowservice.CreateWorkerDeploymentRequest{
Namespace: "default",
DeploymentName: "my-app",
})
// Create a version with Lambda compute config
client.CreateWorkerDeploymentVersion(ctx, &workflowservice.CreateWorkerDeploymentVersionRequest{
Namespace: "default",
DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{
DeploymentName: "my-app",
BuildId: "build-1",
},
ComputeConfig: &computepb.ComputeConfig{
ScalingGroups: map[string]*computepb.ComputeConfigScalingGroup{
"default": {
Provider: &computepb.ComputeProvider{
Type: "aws-lambda",
Details: /* Lambda ARN, role ARN, external ID */,
},
},
},
},
})
5. Set the version as current
If you created the version through the Temporal UI, the version is already current and you can skip this step.
If you used the CLI or SDK, set the version as current. Without this step, tasks on the Task Queue will not route to the version, and Temporal will not invoke the Lambda function.
temporal worker deployment set-current-version \
--deployment-name my-app \
--build-id build-1
6. Verify the deployment
Start a Workflow on the same Task Queue to confirm that Temporal invokes your Lambda Worker.
temporal workflow start \
--task-queue my-task-queue \
--type MyWorkflow \
--input '"Hello, serverless!"'
When the task lands on the Task Queue with no active pollers, Temporal detects the compute provider configuration and invokes your Lambda function. The Worker starts, connects to Temporal, picks up the task, and processes it.
You can verify the invocation by checking:
- Temporal UI: The Workflow execution should show task completions in the event history.
- AWS CloudWatch Logs: The Lambda function's log group (
/aws/lambda/my-temporal-worker) should show invocation logs with the Worker startup, task processing, and graceful shutdown.