home / skills / giuseppe-trisciuoglio / developer-kit / aws-cloudformation-lambda

This skill helps you design and implement AWS CloudFormation patterns for Lambda, API Gateway, and event-driven stacks with best practices.

npx playbooks add skill giuseppe-trisciuoglio/developer-kit --skill aws-cloudformation-lambda

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
44.4 KB
---
name: aws-cloudformation-lambda
description: Provides AWS CloudFormation patterns for Lambda functions, layers, event sources, and integrations. Use when creating Lambda functions with CloudFormation, configuring API Gateway, Step Functions, EventBridge, SQS, SNS triggers, and implementing template structure with Parameters, Outputs, Mappings, Conditions, cross-stack references, and best practices for cold start optimization.
category: aws
tags: [aws, cloudformation, lambda, serverless, functions, api-gateway, step-functions, events, infrastructure, iaac]
version: 1.0.0
allowed-tools: Read, Write, Bash
---

# AWS CloudFormation Lambda Serverless

## Overview

Create production-ready serverless infrastructure using AWS CloudFormation templates. This skill covers Lambda functions, layers, event sources, API Gateway, Step Functions, cold start optimization, and best practices for parameters, outputs, and cross-stack references.

## When to Use

Use this skill when:
- Creating new Lambda functions with CloudFormation
- Configuring Lambda layers for shared code
- Integrating Lambda with API Gateway (REST and HTTP API)
- Implementing event sources (SQS, SNS, EventBridge, S3, DynamoDB)
- Creating Step Functions with Lambda workflows
- Optimizing cold start and performance
- Organizing templates with Parameters, Outputs, Mappings, Conditions
- Implementing cross-stack references with export/import
- Using Transform for macros and reuse

## Instructions

Follow these steps to create Lambda infrastructure with CloudFormation:

1. **Define Function Parameters**: Specify runtime, handler, and memory settings
2. **Configure Code Source**: Set S3 bucket and key for deployment package
3. **Set Up IAM Role**: Define execution role with minimal permissions
4. **Add Environment Variables**: Configure function settings securely
5. **Implement Event Sources**: Connect triggers (API Gateway, SQS, SNS, etc.)
6. **Configure Layers**: Add shared code libraries for reuse
7. **Set Up Dead Letter Queue**: Configure error handling for failed invocations
8. **Add Monitoring**: Enable X-Ray tracing and CloudWatch logs

For complete examples, see the [EXAMPLES.md](references/examples.md) file.

## Examples

The following examples demonstrate common Lambda patterns:

### Example 1: Lambda Function

```yaml
LambdaFunction:
  Type: AWS::Lambda::Function
  Properties:
    FunctionName: !Sub "${AWS::StackName}-handler"
    Runtime: python3.11
    Handler: app.handler
    Code:
      S3Bucket: !Ref CodeBucket
      S3Key: lambda/function.zip
    MemorySize: 256
    Timeout: 30
    Role: !GetAtt LambdaRole.Arn
```

### Example 2: Lambda with API Gateway

```yaml
ApiGateway:
  Type: AWS::ApiGateway::RestApi
  Properties:
    Name: !Sub "${AWS::StackName}-api"
    Description: API for Lambda function

LambdaPermission:
  Type: AWS::Lambda::Permission
  Properties:
    FunctionName: !Ref LambdaFunction
    Action: lambda:InvokeFunction
    Principal: apigateway.amazonaws.com
```

### Example 3: Lambda Layer

```yaml
LambdaLayer:
  Type: AWS::Lambda::LayerVersion
  Properties:
    LayerName: !Sub "${AWS::StackName}-shared-layer"
    CompatibleRuntimes:
      - python3.11
    Content:
      S3Bucket: !Ref LayerBucket
      S3Key: layers/shared.zip
```

For complete production-ready examples, see [EXAMPLES.md](references/examples.md).

## CloudFormation Template Structure

### Base Template with Standard Format

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function with API Gateway integration

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Function Configuration
        Parameters:
          - FunctionName
          - Runtime
          - Handler
      - Label:
          default: Deployment Settings
        Parameters:
          - Environment
          - DeployStage

Parameters:
  FunctionName:
    Type: String
    Default: my-lambda-function
    Description: Name of the Lambda function

  Runtime:
    Type: String
    Default: python3.11
    AllowedValues:
      - python3.8
      - python3.9
      - python3.10
      - python3.11
      - nodejs18.x
      - nodejs20.x
      - java11
      - java17
      - java21

  Handler:
    Type: String
    Default: index.handler

  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - production

  DeployStage:
    Type: String
    Default: dev

Mappings:
  EnvironmentConfig:
    dev:
      MemorySize: 128
      Timeout: 30
      ReservedConcurrentExecutions: 5
    staging:
      MemorySize: 256
      Timeout: 60
      ReservedConcurrentExecutions: 20
    production:
      MemorySize: 512
      Timeout: 120
      ReservedConcurrentExecutions: 100

Conditions:
  IsProduction: !Equals [!Ref Environment, production]
  IsDev: !Equals [!Ref Environment, dev]

Transform:
  - AWS::Serverless-2016-10-31

Resources:
  # Lambda Function
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Ref FunctionName
      Runtime: !Ref Runtime
      Handler: !Ref Handler
      Code:
        S3Bucket: !Ref SourceBucket
        S3Key: !Sub "lambda/${Environment}/function.zip"
      MemorySize: !FindInMap [EnvironmentConfig, !Ref Environment, MemorySize]
      Timeout: !FindInMap [EnvironmentConfig, !Ref Environment, Timeout]
      Role: !GetAtt LambdaExecutionRole.Arn
      Environment:
        Variables:
          ENVIRONMENT: !Ref Environment
          LOG_LEVEL: !If [IsProduction, INFO, DEBUG]
      Tags:
        - Key: Environment
          Value: !Ref Environment
        - Key: Project
          Value: !Ref ProjectName

Outputs:
  LambdaFunctionArn:
    Description: ARN of the Lambda function
    Value: !GetAtt MyLambdaFunction.Arn
    Export:
      Name: !Sub "${AWS::StackName}-LambdaFunctionArn"
```

## Best Practices for Parameters

### AWS-Specific Parameter Types

```yaml
Parameters:
  # AWS-specific types for validation
  VPCId:
    Type: AWS::EC2::VPC::Id
    Description: VPC where Lambda will run

  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Description: Subnets for Lambda VPC config

  SecurityGroupIds:
    Type: List<AWS::EC2::SecurityGroup::Id>
    Description: Security groups for Lambda

  LambdaRuntime:
    Type: AWS::Lambda::Runtime
    Description: Lambda runtime selection

  IAMRoleArn:
    Type: AWS::IAM::Role::Arn
    Description: IAM role for Lambda execution

  S3BucketForCode:
    Type: AWS::S3::Bucket
    Description: S3 bucket for Lambda code

  KMSKeyArn:
    Type: AWS::KMS::Key::Arn
    Description: KMS key for environment variables
```

### Parameter Constraints

```yaml
Parameters:
  FunctionName:
    Type: String
    Default: my-function
    Description: Lambda function name
    ConstraintDescription: Must be 1-64 characters, alphanumeric and hyphens
    MinLength: 1
    MaxLength: 64
    AllowedPattern: "[a-zA-Z0-9-_]+"

  MemorySize:
    Type: Number
    Default: 128
    Description: Memory allocation in MB
    MinValue: 128
    MaxValue: 10240
    ConstraintDescription: Must be between 128 and 10240 MB

  Timeout:
    Type: Number
    Default: 30
    Description: Function timeout in seconds
    MinValue: 1
    MaxValue: 900
    ConstraintDescription: Must be between 1 and 900 seconds

  EnvironmentName:
    Type: String
    Default: dev
    Description: Deployment environment
    AllowedValues:
      - dev
      - staging
      - production
    ConstraintDescription: Must be dev, staging, or production
```

### SSM Parameter References

```yaml
Parameters:
  DatabaseConnectionString:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /myapp/database/connection-string
    Description: Database connection string from SSM

  ApiKey:
    Type: AWS::SSM::Parameter::Value<SecureString>
    Default: /myapp/external-api/key
    Description: API key from SSM Parameter Store
```

## Outputs and Cross-Stack References

### Export/Import Patterns

```yaml
# Stack A - Network Stack
AWSTemplateFormatVersion: 2010-09-09
Description: Network infrastructure stack

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-vpc"

Outputs:
  VPCId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub "${AWS::StackName}-VPCId"

  PublicSubnetIds:
    Description: Public subnet IDs
    Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]]
    Export:
      Name: !Sub "${AWS::StackName}-PublicSubnetIds"

  PrivateSubnetIds:
    Description: Private subnet IDs
    Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
    Export:
      Name: !Sub "${AWS::StackName}-PrivateSubnetIds"

  LambdaSecurityGroupId:
    Description: Security group ID for Lambda
    Value: !Ref LambdaSecurityGroup
    Export:
      Name: !Sub "${AWS::StackName}-LambdaSecurityGroupId"
```

```yaml
# Stack B - Application Stack (imports from Stack A)
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda application stack

Parameters:
  NetworkStackName:
    Type: String
    Default: network-stack
    Description: Name of the network stack

Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-processor"
      Runtime: python3.11
      Handler: index.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/function.zip
      Role: !GetAtt LambdaExecutionRole.Arn
      VpcConfig:
        SecurityGroupIds:
          - !ImportValue
            !Sub "${NetworkStackName}-LambdaSecurityGroupId"
        SubnetIds:
          - !Select [0, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]]
          - !Select [1, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]]
```

### Nested Stacks for Modularity

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Main stack with nested Lambda stacks

Resources:
  # Nested stack for Lambda functions
  LambdaFunctionsStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/bucket/lambda-functions.yaml
      TimeoutInMinutes: 15
      Parameters:
        Environment: !Ref Environment
        FunctionNamePrefix: !Ref FunctionNamePrefix

  # Nested stack for API Gateway
  ApiGatewayStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/bucket/api-gateway.yaml
      TimeoutInMinutes: 15
      Parameters:
        Environment: !Ref Environment
        LambdaFunctionArn: !GetAtt LambdaFunctionsStack.Outputs.FunctionArn
```

## Lambda Functions with Advanced Configurations

### Lambda Base with VPC and Environment

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function with VPC, environment variables, and monitoring

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - production

  VpcConfig:
    Type: String
    Default: full
    AllowedValues:
      - none
      - full
      - internal

Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-lambda-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: !Sub "${AWS::StackName}-vpc-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - ec2:CreateNetworkInterface
                  - ec2:DescribeNetworkInterfaces
                  - ec2:DeleteNetworkInterface
                Resource: "*"
        - PolicyName: !Sub "${AWS::StackName}-secrets-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource: !Ref SecretsArn

  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-processor"
      Runtime: python3.11
      Handler: index.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: !Sub "lambda/${Environment}/function.zip"
      MemorySize: 256
      Timeout: 60
      Role: !GetAtt LambdaExecutionRole.Arn
      VpcConfig:
        !If
          - IsFullVpc
          - SecurityGroupIds:
              - !Ref LambdaSecurityGroup
            SubnetIds:
              - !Ref PrivateSubnet1
              - !Ref PrivateSubnet2
          - !Ref AWS::NoValue
      Environment:
        Variables:
          ENVIRONMENT: !Ref Environment
          LOG_LEVEL: !If [IsProduction, INFO, DEBUG]
          DB_HOST: !Ref DatabaseHost
          DB_NAME: !Ref DatabaseName
      TracingConfig:
        Mode: !If [IsProduction, Active, PassThrough]
      Tags:
        - Key: Environment
          Value: !Ref Environment
        - Key: Project
          Value: !Ref ProjectName
        - Key: CostCenter
          Value: !Ref CostCenter

  LambdaFunctionUrl:
    Type: AWS::Lambda::Url
    Properties:
      AuthType: AWS_IAM
      TargetFunctionArn: !GetAtt MyLambdaFunction.Arn
      Cors:
        AllowCredentials: true
        AllowHeaders:
          - "*"
        AllowMethods:
          - GET
          - POST
        AllowOrigins:
          - !If [IsProduction, !Ref ProductionCorsOrigin, "*"]
        MaxAge: 86400

Conditions:
  IsFullVpc: !Equals [!Ref VpcConfig, full]
  IsProduction: !Equals [!Ref Environment, production]
```

### Lambda with Provisioned Concurrency

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-api"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/api.zip
      MemorySize: 512
      Timeout: 30
      Role: !GetAtt LambdaExecutionRole.Arn

  ProvisionedConcurrencyConfig:
    Type: AWS::Lambda::ProvisionedConcurrencyConfig
    Properties:
      FunctionName: !Ref MyLambdaFunction
      ProvisionedConcurrentExecutions: 5
      ProvisionedExecutionTarget:
        AllocationStrategy: PRICE_OPTIMIZED
```

## Lambda Layers

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function with layers

Resources:
  CommonLibraryLayer:
    Type: AWS::Lambda::LayerVersion
    Properties:
      LayerName: !Sub "${AWS::StackName}-common-lib"
      Description: Common utilities for Lambda functions
      Content:
        S3Bucket: !Ref LayersBucket
        S3Key: layers/common-lib.zip
      CompatibleRuntimes:
        - python3.9
        - python3.10
        - python3.11
      CompatibleArchitectures:
        - x86_64
        - arm64

  DataProcessingLayer:
    Type: AWS::Lambda::LayerVersion
    Properties:
      LayerName: !Sub "${AWS::StackName}-data-processing"
      Description: Data processing utilities
      Content:
        S3Bucket: !Ref LayersBucket
        S3Key: layers/data-processing.zip
      CompatibleRuntimes:
        - python3.11

  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-processor"
      Runtime: python3.11
      Handler: index.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/processor.zip
      Layers:
        - !Ref CommonLibraryLayer
        - !Ref DataProcessingLayer
```

## API Gateway Integration

### API Gateway REST with Lambda Proxy

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: API Gateway REST with Lambda proxy integration

Resources:
  ApiGatewayRestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: !Sub "${AWS::StackName}-api"
      Description: REST API for Lambda backend
      EndpointConfiguration:
        Types:
          - REGIONAL
      MinimumCompressionSize: 1024
      DisableExecuteApiEndpoint: false

  ApiGatewayResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      RestApiId: !Ref ApiGatewayRestApi
      ParentId: !GetAtt ApiGatewayRestApi.RootResourceId
      PathPart: items

  ApiGatewayMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref ApiGatewayRestApi
      ResourceId: !Ref ApiGatewayResource
      HttpMethod: GET
      AuthorizationType: COGNITO_USER_POOLS
      AuthorizerId: !Ref ApiGatewayAuthorizer
      RequestParameters:
        method.request.querystring.id: true
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations"
        IntegrationResponses:
          - StatusCode: 200
            ResponseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
              method.response.header.Content-Type: "'application/json'"
        PassthroughBehavior: WHEN_NO_MATCH
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
          ResponseParameters:
            method.response.header.Access-Control-Allow-Origin: true

  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: ApiGatewayMethod
    Properties:
      RestApiId: !Ref ApiGatewayRestApi
      StageName: !Ref DeployStage
      StageDescription:
        LoggingLevel: !If [IsProduction, INFO, ERROR]
        DataTraceEnabled: !If [IsProduction, false, true]
        MetricsEnabled: true
        ThrottlingRateLimit: 100
        ThrottlingBurstLimit: 200
      Variables:
        Environment: !Ref Environment

  LambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref MyLambdaFunction
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayRestApi}/*/*/*"

  ApiGatewayAuthorizer:
    Type: AWS::ApiGateway::Authorizer
    Properties:
      Name: !Sub "${AWS::StackName}-authorizer"
      Type: COGNITO_USER_POOLS
      RestApiId: !Ref ApiGatewayRestApi
      ProviderARNs:
        - !Ref CognitoUserPoolArn
      IdentitySource: method.request.header.Authorization
      AuthorizerResultTtlInSeconds: 300

Outputs:
  ApiEndpoint:
    Description: API Gateway endpoint URL
    Value: !Sub "https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${DeployStage}/items"
```

### API Gateway HTTP API with Lambda

```yaml
Resources:
  HttpApi:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: !Sub "${AWS::StackName}-http-api"
      ProtocolType: HTTP
      CorsConfiguration:
        AllowOrigins:
          - !If [IsProduction, !Ref ProductionDomain, "*"]
        AllowMethods:
          - GET
          - POST
          - PUT
          - DELETE
          - OPTIONS
        AllowHeaders:
          - "*"
        MaxAge: 86400

  HttpApiStage:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      ApiId: !Ref HttpApi
      StageName: !Ref DeployStage
      AutoDeploy: true
      DefaultRouteSettings:
        DetailedMetricsEnabled: true
        ThrottlingBurstLimit: 100
        ThrottlingRateLimit: 50

  HttpApiIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref HttpApi
      IntegrationType: AWS_PROXY
      IntegrationUri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations"
      PayloadFormatVersion: "2.0"

  HttpApiRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref HttpApi
      RouteKey: ANY /items/{id}
      Target: !Sub "integrations/${HttpApiIntegration.Id}"
```

## Event Sources

### SQS Event Source

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-sqs-processor"
      Runtime: python3.11
      Handler: sqs_handler.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/sqs-processor.zip
      Timeout: 300
      Role: !GetAtt LambdaExecutionRole.Arn

  Queue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub "${AWS::StackName}-queue"
      VisibilityTimeout: 360
      MessageRetentionPeriod: 1209600
      RedrivePolicy:
        deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn
        maxReceiveCount: 5

  DeadLetterQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub "${AWS::StackName}-dlq"

  EventSourceMapping:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      FunctionName: !Ref MyLambdaFunction
      EventSourceArn: !GetAtt Queue.Arn
      BatchSize: 10
      MaximumBatchingWindowInSeconds: 60
      ScalingConfig:
        MaximumConcurrency: 10
      FilterCriteria:
        Filters:
          - Pattern: '{"body": {"messageType": ["order", "notification"]}}'
      Enabled: true

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-sqs-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole
      Policies:
        - PolicyName: !Sub "${AWS::StackName}-dlq-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - sqs:DeleteMessage
                  - sqs:ReceiveMessage
                Resource: !GetAtt DeadLetterQueue.Arn
```

### SNS Event Source

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-sns-processor"
      Runtime: python3.11
      Handler: sns_handler.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/sns-processor.zip

  Topic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub "${AWS::StackName}-topic"
      DisplayName: !Sub "${AWS::StackName} Notifications"
      Subscription:
        - Endpoint: !GetAtt MyLambdaFunction.Arn
          Protocol: lambda
      Tags:
        - Key: Environment
          Value: !Ref Environment

  TopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref Topic
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: sns.amazonaws.com
            Action: sns:Publish
            Resource: !Ref Topic

  LambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref MyLambdaFunction
      Action: lambda:InvokeFunction
      Principal: sns.amazonaws.com
      SourceArn: !Ref Topic
```

### EventBridge (CloudWatch Events)

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-scheduler"
      Runtime: python3.11
      Handler: scheduler.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/scheduler.zip
      Timeout: 300
      Role: !GetAtt LambdaExecutionRole.Arn

  ScheduledRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub "${AWS::StackName}-scheduled-rule"
      ScheduleExpression: "rate(5 minutes)"
      State: ENABLED
      Targets:
        - Id: !Ref MyLambdaFunction
          Arn: !GetAtt MyLambdaFunction.Arn
          RetryPolicy:
            MaximumEventAgeInSeconds: 86400
            MaximumRetryAttempts: 3

  LambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref MyLambdaFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt ScheduledRule.Arn
```

### S3 Event Source

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-s3-processor"
      Runtime: python3.11
      Handler: s3_handler.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/s3-processor.zip
      Timeout: 300
      Role: !GetAtt LambdaExecutionRole.Arn

  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-uploads-${AWS::AccountId}-${AWS::Region}"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      VersioningConfiguration:
        Status: Enabled
      NotificationConfiguration:
        LambdaConfigurations:
          - Event: s3:ObjectCreated:*
            Filter:
              S3Key:
                Rules:
                  - Name: suffix
                    Value: .csv
            Function: !GetAtt MyLambdaFunction.Arn
          - Event: s3:ObjectCreated:*
            Filter:
              S3Key:
                Rules:
                  - Name: prefix
                    Value: processed/
            Function: !GetAtt MyLambdaFunction.Arn

  LambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref MyLambdaFunction
      Action: lambda:InvokeFunction
      Principal: s3.amazonaws.com
      SourceArn: !GetAtt Bucket.Arn
```

## Step Functions Integration

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Step Functions with Lambda tasks

Resources:
  # Lambda functions for Step Functions
  ProcessItemFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-process-item"
      Runtime: python3.11
      Handler: process_item.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/process-item.zip
      Timeout: 300
      Role: !GetAtt LambdaExecutionRole.Arn

  ValidateItemFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-validate-item"
      Runtime: python3.11
      Handler: validate_item.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/validate-item.zip
      Timeout: 60
      Role: !GetAtt LambdaExecutionRole.Arn

  NotifyCompletionFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-notify-completion"
      Runtime: python3.11
      Handler: notify.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/notify.zip
      Timeout: 60
      Role: !GetAtt LambdaExecutionRole.Arn

  # Step Functions State Machine
  ProcessingStateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      StateMachineName: !Sub "${AWS::StackName}-processor"
      StateMachineType: STANDARD
      DefinitionString: !Sub |
        {
          "Comment": "Item processing state machine",
          "StartAt": "ValidateItem",
          "States": {
            "ValidateItem": {
              "Type": "Task",
              "Resource": "${ValidateItemFunction.Arn}",
              "Retry": [
                {
                  "ErrorEquals": ["States.TaskFailed"],
                  "IntervalSeconds": 2,
                  "MaxAttempts": 3,
                  "BackoffRate": 2
                }
              ],
              "Next": "ProcessItem"
            },
            "ProcessItem": {
              "Type": "Task",
              "Resource": "${ProcessItemFunction.Arn}",
              "Retry": [
                {
                  "ErrorEquals": ["States.TaskFailed"],
                  "IntervalSeconds": 5,
                  "MaxAttempts": 2,
                  "BackoffRate": 2
                }
              ],
              "Catch": [
                {
                  "ErrorEquals": ["States.ALL"],
                  "Next": "HandleFailure"
                }
              ],
              "Next": "NotifyCompletion"
            },
            "NotifyCompletion": {
              "Type": "Task",
              "Resource": "${NotifyCompletionFunction.Arn}",
              "End": true
            },
            "HandleFailure": {
              "Type": "Pass",
              "End": true
            }
          }
        }
      RoleArn: !GetAtt StepFunctionsExecutionRole.Arn
      LoggingConfiguration:
        Level: ALL
        IncludeExecutionData: true
        Destinations:
          - CloudWatchLogsLogGroup: !Ref StateMachineLogGroup

  StepFunctionsExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-sfn-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: states.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub "${AWS::StackName}-lambda-invoke"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - lambda:InvokeFunction
                Resource:
                  - !GetAtt ProcessItemFunction.Arn
                  - !GetAtt ValidateItemFunction.Arn
                  - !GetAtt NotifyCompletionFunction.Arn

  StateMachineLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/state-machine/${AWS::StackName}"
      RetentionInDays: 30
```

## Cold Start Optimization

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function optimized for cold start

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - production

Resources:
  # Use AWS::Serverless::Function for better cold start
  OptimizedLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-optimized"
      CodeUri: s3://bucket/function.zip
      Handler: app.handler
      Runtime: python3.11
      MemorySize: 512
      Timeout: 30
      EphemeralStorage:
        Size: 1024
      SnapStart:
        ApplyOn: PublishedVersions
      ProvisionedConcurrencyConfig:
        ProvisionedConcurrentExecutions: !If [IsProduction, 5, 0]
      Layers:
        - !Ref CommonDependenciesLayer
      Environment:
        Variables:
          PYTHONPATH: "/var/task:/opt"
      Policies:
        - AWSLambdaVPCAccessExecutionRole
        - AmazonS3ReadOnlyAccess
      VpcConfig:
        SecurityGroupIds:
          - !Ref LambdaSecurityGroup
        SubnetIds: !Ref PrivateSubnetIds
      EventInvokeConfig:
        MaximumEventAgeInSeconds: 3600
        MaximumRetryAttempts: 2

  # Optimized layer with pre-installed dependencies
  CommonDependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: !Sub "${AWS::StackName}-dependencies"
      Description: Pre-installed Python dependencies for Lambda
      ContentUri: s3://bucket/layers/dependencies.zip
      CompatibleRuntimes:
        - python3.11
      CompatibleArchitectures:
        - x86_64
      RetentionPolicy: Retain

Conditions:
  IsProduction: !Equals [!Ref Environment, production]

Outputs:
  FunctionArn:
    Description: Lambda function ARN
    Value: !GetAtt OptimizedLambdaFunction.Arn
  FunctionUrl:
    Description: Lambda function URL for direct invocation
    Value: !GetAtt OptimizedLambdaFunction.Url
```

## Monitoring and Logging

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda with comprehensive monitoring

Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-monitored"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/function.zip
      Role: !GetAtt LambdaExecutionRole.Arn
      TracingConfig:
        Mode: Active

  # Log group with retention
  LambdaLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-monitored"
      RetentionInDays: 30
      KmsKeyId: !Ref LogKmsKey

  # Metric filter for errors
  ErrorMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref LambdaLogGroup
      FilterPattern: 'ERROR'
      MetricTransformations:
        - MetricValue: "1"
          MetricNamespace: !Sub "${AWS::StackName}/Lambda"
          MetricName: ErrorCount

  # CloudWatch Alarms
  HighErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${AWS::StackName}-high-error-rate"
      AlarmDescription: Alert when error rate exceeds threshold
      MetricName: Errors
      Namespace: AWS/Lambda
      Dimensions:
        - Name: FunctionName
          Value: !Ref MyLambdaFunction
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 5
      Threshold: 10
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Ref AlertTopic

  HighThrottlesAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${AWS::StackName}-high-throttles"
      AlarmDescription: Alert when throttling occurs
      MetricName: Throttles
      Namespace: AWS/Lambda
      Dimensions:
        - Name: FunctionName
          Value: !Ref MyLambdaFunction
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 3
      Threshold: 5
      ComparisonOperator: GreaterThanThreshold

  AlertTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub "${AWS::StackName}-alerts"

  # Lambda Destination for async invocations
  LambdaDestination:
    Type: AWS::Lambda::EventInvokeConfig
    Properties:
      FunctionName: !Ref MyLambdaFunction
      MaximumEventAgeInSeconds: 3600
      MaximumRetryAttempts: 2
      Qualifier: $LATEST
```

## Conditions and Transform

### Conditions for Environment-Specific Resources

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda with conditional resources

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - production
    Description: Deployment environment

Conditions:
  IsProduction: !Equals [!Ref Environment, production]
  IsStaging: !Equals [!Ref Environment, staging]
  CreateDeadLetterQueue: !Or [!Equals [!Ref Environment, staging], !Equals [!Ref Environment, production]]
  EnableXray: !Not [!Equals [!Ref Environment, dev]]

Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-function"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: !Sub "lambda/${Environment}/function.zip"
      Timeout: !If [IsProduction, 60, 30]
      MemorySize: !If [IsProduction, 512, 256]
      Role: !GetAtt LambdaExecutionRole.Arn
      TracingConfig: !If
        - EnableXray
        - Mode: Active
        - !Ref AWS::NoValue
      Environment:
        Variables:
          LOG_LEVEL: !If [IsProduction, INFO, DEBUG]

  DeadLetterQueue:
    Type: AWS::SQS::Queue
    Condition: CreateDeadLetterQueue
    Properties:
      QueueName: !Sub "${AWS::StackName}-dlq"
```

### Transform for Code Reuse

```yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Description: Using SAM Transform for Lambda

Globals:
  Function:
    Timeout: 30
    Runtime: python3.11
    Tracing: Active
    Environment:
      Variables:
        LOG_LEVEL: INFO
    Metadata:
      DockerBuild: true
      Dockerfile: Dockerfile
      DockerContext: lambda_function/

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-sam-function"
      Handler: app.handler
      CodeUri: lambda_function/
      Policies:
        - S3ReadPolicy:
            BucketName: !Ref DataBucket
        - DynamoDBReadPolicy:
            TableName: !Ref DataTable
      Events:
        Api:
          Type: Api
          Properties:
            Path: /items
            Method: get
        SqsQueue:
          Type: SQS
          Properties:
            Queue: !GetAtt Queue.Arn
            BatchSize: 10
      AutoPublishAlias: !Ref Environment
      DeploymentPreference:
        Type: !Ref DeploymentConfig
        Alarms:
          - !Ref ErrorAlarm
          - !Ref LatencyAlarm

  DataTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: !Sub "${AWS::StackName}-table"
      PrimaryKey:
        Name: id
        Type: String

Parameters:
  Environment:
    Type: String
    Default: dev
  DeploymentConfig:
    Type: String
    Default: AllAtOnce
    AllowedValues:
      - Canary10Percent5Minutes
      - Canary10Percent10Minutes
      - Canary10Percent15Minutes
      - AllAtOnce
      - Linear10PercentEvery1Minute
      - Linear10PercentEvery2Minutes
      - Linear10PercentEvery3Minutes
```

## Best Practices

### Security

- Use IAM roles with minimum necessary permissions
- Encrypt environment variables with KMS
- Use VPC for private resource access
- Configure resource-based policies for invocations
- Enable AWS WAF for API Gateway protection
- Use API keys and throttling for protection

### Performance

- Choose memory size based on profiling
- Use provisioned concurrency for critical latency
- Optimize package size for cold start
- Use layers for shared dependencies
- Pre-compile code for interpreted languages
- Consider SnapStart for Java/.NET

### Monitoring

- Enable detailed metrics and tracing
- Configure appropriate log retention
- Create alarms for errors and throttling
- Use Lambda destinations for async error handling
- Implement distributed tracing

### Deployment

- Use change sets before deployment
- Test templates with cfn-lint
- Organize stacks by lifecycle and ownership
- Use nested stacks for modularity
- Implement blue/green deployments

## CloudFormation Stack Management Best Practices

### Stack Policies

Stack policies protect stack resources from unintentional updates that could cause critical changes or deletions.

```yaml
Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      # Function configuration

# Stack policy to protect Lambda function from updates
StackPolicy:
  Type: AWS::CloudFormation::StackPolicy
  Properties:
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal: "*"
          Action: "Update:*"
          Resource: "*"
        - Effect: Deny
          Principal: "*"
          Action:
            - Update:Replace
            - Update:Delete
          Resource:
            - LogicalId: LambdaFunction
              ResourceType: AWS::Lambda::Function
          Condition:
            StringEquals:
              ResourceAttribute: Arn:
                Fn::Ref: LambdaFunction
```

### Termination Protection

Enable termination protection to prevent accidental stack deletion, especially for production environments.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function with termination protection

Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-function"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/function.zip
      Role: !GetAtt LambdaExecutionRole.Arn

# Enable termination protection (must be set during stack creation)
# This is a stack-level attribute, not a resource
```

**Important**: Termination protection must be enabled during stack creation via AWS Console, CLI, or API:

```bash
aws cloudformation create-stack \
  --stack-name my-lambda-stack \
  --template-body file://template.yaml \
  --enable-termination-protection \
  --capabilities CAPABILITY_IAM
```

### Drift Detection

Detect when infrastructure has diverged from the CloudFormation template.

```yaml
Resources:
  # All Lambda resources support drift detection
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-function"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/function.zip
      Role: !GetAtt LambdaExecutionRole.Arn
      Environment:
        Variables:
          ENVIRONMENT: !Ref Environment
          LOG_LEVEL: !Ref LogLevel
```

**CLI commands for drift detection:**

```bash
# Detect drift on a stack
aws cloudformation detect-drift --stack-name my-lambda-stack

# Get drift detection status
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id <detection-id>

# Get resource drift status
aws cloudformation describe-stack-resource-drifts \
  --stack-name my-lambda-stack

# Compare actual vs expected resource properties
aws cloudformation get-stack-policy --stack-name my-lambda-stack
```

### Change Sets

Use change sets to preview and review stack changes before execution.

```yaml
Resources:
  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-function"
      Runtime: python3.11
      Handler: app.handler
      Code:
        S3Bucket: !Ref CodeBucket
        S3Key: lambda/function.zip
      Role: !GetAtt LambdaExecutionRole.Arn
      MemorySize: !Ref MemorySize
      Timeout: !Ref Timeout

Parameters:
  MemorySize:
    Type: Number
    Default: 256
    Description: Memory allocation in MB

  Timeout:
    Type: Number
    Default: 30
    Description: Function timeout in seconds
```

**Change set workflow:**

```bash
# 1. Create a change set
aws cloudformation create-change-set \
  --stack-name my-lambda-stack \
  --change-set-name my-changeset \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_IAM \
  --parameters ParameterKey=MemorySize,ParameterValue=512

# 2. Describe the change set to review changes
aws cloudformation describe-change-set \
  --stack-name my-lambda-stack \
  --change-set-name my-changeset

# 3. Execute the change set
aws cloudformation execute-change-set \
  --stack-name my-lambda-stack \
  --change-set-name my-changeset

# Or delete if changes are not acceptable
aws cloudformation delete-change-set \
  --stack-name my-lambda-stack \
  --change-set-name my-changeset
```

**Change set types:**
- `CREATE`: For new stacks
- `UPDATE`: For existing stacks
- `IMPORT`: For importing existing resources

## Related Resources

- [AWS Lambda Documentation](https://docs.aws.amazon.com/lambda/)
- [AWS CloudFormation User Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/)
- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/)
- [Lambda Best Practices](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html)

## Constraints and Warnings

### Resource Limits

- **Function Limits**: Maximum number of Lambda functions per region is account-dependent
- **Concurrent Execution Limits**: Default safety limit is 1000 concurrent executions per region
- **Timeout Limits**: Maximum timeout is 15 minutes (900 seconds)
- **Memory Limits**: Maximum memory is 10,240 MB (10 GB)

### Deployment Constraints

- **Function Size**: Maximum deployment package size is 50 MB (zipped) or 250 MB (unzipped)
- **Layer Size**: Maximum layer size is 250 MB (unzipped)
- **Environment Variables**: Maximum 4 KB for environment variables
- **Concurrency Limits**: Reserved concurrency cannot exceed account limit

### Operational Constraints

- **Cold Starts**: Cold starts add latency to first invocation of each instance
- **VPC Networking**: Lambda in VPC has ENI limits and potential cold start delays
- **Event Source Limits**: Event sources have rate limits that can trigger Lambda throttling
- **Dead Letter Queues**: Failed async invocations with no DLQ are lost

### Security Constraints

- **Execution Role**: Lambda functions require IAM execution roles with appropriate permissions
- **Resource Policies**: Resource-based policies required for cross-account access
- **VPC Endpoints**: Private API requires VPC endpoints for AWS service access
- **Environment Variable Security**: Environment variables are encrypted at rest but visible in console

### Cost Considerations

- **Provisioned Concurrency**: Provisioned concurrency incurs costs even when unused
- **Request Duration**: Longer function duration directly increases costs
- **Memory Allocation**: Higher memory settings cost more even if not utilized
- **Data Transfer**: Data transfer costs apply for responses and external calls
- **Ephemeral Storage**: Ephemeral storage (/tmp) costs based on size and duration

### Performance Constraints

- **SnapStart**: SnapStart only available for specific runtimes and versions
- **Layer Versioning**: Modifying layer versions requires function update
- **X-Ray Tracing**: X-Ray tracing adds latency and costs
- **Async Invocation**: Async invocations have retry limits and potential duplication

## Additional Files

For complete details on resources and their properties, see:
- [REFERENCE.md](references/reference.md) - Detailed reference guide for all CloudFormation resources
- [EXAMPLES.md](references/examples.md) - Complete production-ready examples

Overview

This skill provides reusable AWS CloudFormation patterns for building production-ready Lambda-based serverless infrastructure. It covers functions, layers, event sources, API Gateway, Step Functions, and integrations with SQS, SNS, EventBridge and other AWS services. It also includes template structure and best practices for parameters, outputs, cross-stack references, and cold start optimization.

How this skill works

The skill supplies CloudFormation templates and patterns that define Lambda functions, execution roles, layers, VPC configuration, and event source mappings. It shows how to wire API Gateway, Step Functions, EventBridge, SQS, SNS, S3 and DynamoDB triggers, export/import outputs for cross-stack references, and apply Transforms and nested stacks for modularization. Templates include parameter validation, mappings, conditions, and examples for provisioning concurrency and monitoring.

When to use it

  • When creating new Lambda functions and deployment packages with CloudFormation
  • When adding or sharing Lambda layers across functions
  • When integrating Lambda with API Gateway, Step Functions, EventBridge, SQS or SNS
  • When organizing templates with Parameters, Mappings, Conditions, and Outputs
  • When implementing cross-stack references or nested stacks for modular infrastructure
  • When optimizing cold start, provisioning concurrency, and monitoring configuration

Best practices

  • Use AWS-specific parameter types (VPC, Subnet, Role ARNs) to validate inputs and reduce runtime errors
  • Define minimal IAM roles and policies for Lambda execution; prefer least privilege
  • Keep code artifacts in S3 and reference via parameters for repeatable deployments
  • Organize environment-specific settings in Mappings and Conditions rather than hard-coding values
  • Export stable resource identifiers (ARNs, subnet lists) from network stacks and ImportValue in application stacks
  • Use Provisioned Concurrency, warmers, and smaller dependency footprints to reduce cold starts

Example use cases

  • Deploy a Python Lambda with VPC access, environment variables, X-Ray tracing, and CloudWatch logging
  • Create an API Gateway REST or HTTP API connected to a Lambda function with correct LambdaPermission and CORS configuration
  • Build EventBridge rules or SQS/SNS triggers to invoke worker Lambdas with DLQ and retry policies
  • Package shared utilities into a Lambda Layer and reference it from multiple service functions
  • Split infrastructure into a network stack that exports VPC/subnet/security group IDs and an application stack that imports them

FAQ

How do I reduce Lambda cold starts?

Use Provisioned Concurrency for critical paths, minimize package size and dependencies, prefer smaller runtimes, and configure memory/CPU to match workload.

When should I use nested stacks vs. separate stacks?

Use nested stacks for tightly-coupled modules that you deploy together; use separate stacks with exports when teams manage independent lifecycle or when you need clear cross-stack imports.