Create and Configure AWS Lambda Functions

The aws:lambda/function:Function resource, part of the Pulumi AWS provider, defines a Lambda function and its execution environment: code package, runtime, handler, networking, and observability configuration. This guide focuses on five capabilities: Lambda Layers for code sharing, VPC networking for private resource access, EFS integration for persistent storage, CloudWatch logging configuration, and error handling with dead letter queues.

A Lambda function doesn’t stand alone. Real workloads depend on IAM execution roles and may reference VPC subnets, security groups, EFS file systems, or SQS/SNS resources that must exist separately. The examples are intentionally small and won’t run standalone. Combine them with your own IAM roles, networking infrastructure, and event sources. You’ll work with execution roles, code deployment options, VPC configuration, and logging/error handling controls.

Share code across functions with Lambda Layers

Teams often extract common dependencies into Lambda Layers to reduce deployment package sizes and share code across multiple functions.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Common dependencies layer
const example = new aws.lambda.LayerVersion("example", {
    code: new pulumi.asset.FileArchive("layer.zip"),
    layerName: "example_dependencies_layer",
    description: "Common dependencies for Lambda functions",
    compatibleRuntimes: [
        "nodejs20.x",
        "python3.12",
    ],
    compatibleArchitectures: [
        "x86_64",
        "arm64",
    ],
});
// Function using the layer
const exampleFunction = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "example_layered_function",
    role: exampleAwsIamRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.NodeJS20dX,
    layers: [example.arn],
    tracingConfig: {
        mode: "Active",
    },
});
import pulumi
import pulumi_aws as aws

# Common dependencies layer
example = aws.lambda_.LayerVersion("example",
    code=pulumi.FileArchive("layer.zip"),
    layer_name="example_dependencies_layer",
    description="Common dependencies for Lambda functions",
    compatible_runtimes=[
        "nodejs20.x",
        "python3.12",
    ],
    compatible_architectures=[
        "x86_64",
        "arm64",
    ])
# Function using the layer
example_function = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="example_layered_function",
    role=example_aws_iam_role["arn"],
    handler="index.handler",
    runtime=aws.lambda_.Runtime.NODE_JS20D_X,
    layers=[example.arn],
    tracing_config={
        "mode": "Active",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// Common dependencies layer
		example, err := lambda.NewLayerVersion(ctx, "example", &lambda.LayerVersionArgs{
			Code:        pulumi.NewFileArchive("layer.zip"),
			LayerName:   pulumi.String("example_dependencies_layer"),
			Description: pulumi.String("Common dependencies for Lambda functions"),
			CompatibleRuntimes: pulumi.StringArray{
				pulumi.String("nodejs20.x"),
				pulumi.String("python3.12"),
			},
			CompatibleArchitectures: pulumi.StringArray{
				pulumi.String("x86_64"),
				pulumi.String("arm64"),
			},
		})
		if err != nil {
			return err
		}
		// Function using the layer
		_, err = lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:    pulumi.NewFileArchive("function.zip"),
			Name:    pulumi.String("example_layered_function"),
			Role:    pulumi.Any(exampleAwsIamRole.Arn),
			Handler: pulumi.String("index.handler"),
			Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
			Layers: pulumi.StringArray{
				example.Arn,
			},
			TracingConfig: &lambda.FunctionTracingConfigArgs{
				Mode: pulumi.String("Active"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    // Common dependencies layer
    var example = new Aws.Lambda.LayerVersion("example", new()
    {
        Code = new FileArchive("layer.zip"),
        LayerName = "example_dependencies_layer",
        Description = "Common dependencies for Lambda functions",
        CompatibleRuntimes = new[]
        {
            "nodejs20.x",
            "python3.12",
        },
        CompatibleArchitectures = new[]
        {
            "x86_64",
            "arm64",
        },
    });

    // Function using the layer
    var exampleFunction = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "example_layered_function",
        Role = exampleAwsIamRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.NodeJS20dX,
        Layers = new[]
        {
            example.Arn,
        },
        TracingConfig = new Aws.Lambda.Inputs.FunctionTracingConfigArgs
        {
            Mode = "Active",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.LayerVersion;
import com.pulumi.aws.lambda.LayerVersionArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionTracingConfigArgs;
import com.pulumi.asset.FileArchive;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        // Common dependencies layer
        var example = new LayerVersion("example", LayerVersionArgs.builder()
            .code(new FileArchive("layer.zip"))
            .layerName("example_dependencies_layer")
            .description("Common dependencies for Lambda functions")
            .compatibleRuntimes(            
                "nodejs20.x",
                "python3.12")
            .compatibleArchitectures(            
                "x86_64",
                "arm64")
            .build());

        // Function using the layer
        var exampleFunction = new Function("exampleFunction", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("example_layered_function")
            .role(exampleAwsIamRole.arn())
            .handler("index.handler")
            .runtime("nodejs20.x")
            .layers(example.arn())
            .tracingConfig(FunctionTracingConfigArgs.builder()
                .mode("Active")
                .build())
            .build());

    }
}
resources:
  # Common dependencies layer
  example:
    type: aws:lambda:LayerVersion
    properties:
      code:
        fn::FileArchive: layer.zip
      layerName: example_dependencies_layer
      description: Common dependencies for Lambda functions
      compatibleRuntimes:
        - nodejs20.x
        - python3.12
      compatibleArchitectures:
        - x86_64
        - arm64
  # Function using the layer
  exampleFunction:
    type: aws:lambda:Function
    name: example
    properties:
      code:
        fn::FileArchive: function.zip
      name: example_layered_function
      role: ${exampleAwsIamRole.arn}
      handler: index.handler
      runtime: nodejs20.x
      layers:
        - ${example.arn}
      tracingConfig:
        mode: Active

When a function references a Layer, Lambda unpacks the Layer’s contents into /opt at runtime, making libraries and helper code available without bundling them in every function. The layers property accepts up to five Layer ARNs. The compatibleRuntimes and compatibleArchitectures properties on the LayerVersion ensure it works with the function’s runtime and architecture.

Connect to private resources in a VPC

Applications that access RDS databases, ElastiCache clusters, or internal APIs need VPC configuration to place the function in private subnets.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "example_vpc_function",
    role: exampleAwsIamRole.arn,
    handler: "app.handler",
    runtime: aws.lambda.Runtime.Python3d12,
    memorySize: 1024,
    timeout: 30,
    vpcConfig: {
        subnetIds: [
            examplePrivate1.id,
            examplePrivate2.id,
        ],
        securityGroupIds: [exampleLambda.id],
        ipv6AllowedForDualStack: true,
    },
    ephemeralStorage: {
        size: 5120,
    },
    snapStart: {
        applyOn: "PublishedVersions",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="example_vpc_function",
    role=example_aws_iam_role["arn"],
    handler="app.handler",
    runtime=aws.lambda_.Runtime.PYTHON3D12,
    memory_size=1024,
    timeout=30,
    vpc_config={
        "subnet_ids": [
            example_private1["id"],
            example_private2["id"],
        ],
        "security_group_ids": [example_lambda["id"]],
        "ipv6_allowed_for_dual_stack": True,
    },
    ephemeral_storage={
        "size": 5120,
    },
    snap_start={
        "apply_on": "PublishedVersions",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:       pulumi.NewFileArchive("function.zip"),
			Name:       pulumi.String("example_vpc_function"),
			Role:       pulumi.Any(exampleAwsIamRole.Arn),
			Handler:    pulumi.String("app.handler"),
			Runtime:    pulumi.String(lambda.RuntimePython3d12),
			MemorySize: pulumi.Int(1024),
			Timeout:    pulumi.Int(30),
			VpcConfig: &lambda.FunctionVpcConfigArgs{
				SubnetIds: pulumi.StringArray{
					examplePrivate1.Id,
					examplePrivate2.Id,
				},
				SecurityGroupIds: pulumi.StringArray{
					exampleLambda.Id,
				},
				Ipv6AllowedForDualStack: pulumi.Bool(true),
			},
			EphemeralStorage: &lambda.FunctionEphemeralStorageArgs{
				Size: pulumi.Int(5120),
			},
			SnapStart: &lambda.FunctionSnapStartArgs{
				ApplyOn: pulumi.String("PublishedVersions"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "example_vpc_function",
        Role = exampleAwsIamRole.Arn,
        Handler = "app.handler",
        Runtime = Aws.Lambda.Runtime.Python3d12,
        MemorySize = 1024,
        Timeout = 30,
        VpcConfig = new Aws.Lambda.Inputs.FunctionVpcConfigArgs
        {
            SubnetIds = new[]
            {
                examplePrivate1.Id,
                examplePrivate2.Id,
            },
            SecurityGroupIds = new[]
            {
                exampleLambda.Id,
            },
            Ipv6AllowedForDualStack = true,
        },
        EphemeralStorage = new Aws.Lambda.Inputs.FunctionEphemeralStorageArgs
        {
            Size = 5120,
        },
        SnapStart = new Aws.Lambda.Inputs.FunctionSnapStartArgs
        {
            ApplyOn = "PublishedVersions",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionVpcConfigArgs;
import com.pulumi.aws.lambda.inputs.FunctionEphemeralStorageArgs;
import com.pulumi.aws.lambda.inputs.FunctionSnapStartArgs;
import com.pulumi.asset.FileArchive;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Function("example", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("example_vpc_function")
            .role(exampleAwsIamRole.arn())
            .handler("app.handler")
            .runtime("python3.12")
            .memorySize(1024)
            .timeout(30)
            .vpcConfig(FunctionVpcConfigArgs.builder()
                .subnetIds(                
                    examplePrivate1.id(),
                    examplePrivate2.id())
                .securityGroupIds(exampleLambda.id())
                .ipv6AllowedForDualStack(true)
                .build())
            .ephemeralStorage(FunctionEphemeralStorageArgs.builder()
                .size(5120)
                .build())
            .snapStart(FunctionSnapStartArgs.builder()
                .applyOn("PublishedVersions")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:lambda:Function
    properties:
      code:
        fn::FileArchive: function.zip
      name: example_vpc_function
      role: ${exampleAwsIamRole.arn}
      handler: app.handler
      runtime: python3.12
      memorySize: 1024
      timeout: 30
      vpcConfig:
        subnetIds:
          - ${examplePrivate1.id}
          - ${examplePrivate2.id}
        securityGroupIds:
          - ${exampleLambda.id}
        ipv6AllowedForDualStack: true
      ephemeralStorage:
        size: 5120
      snapStart:
        applyOn: PublishedVersions

The vpcConfig property connects your function to specified subnets and security groups, enabling access to private resources. Lambda creates elastic network interfaces in your subnets to route traffic. The ipv6AllowedForDualStack property enables IPv6 alongside IPv4. The ephemeralStorage property controls /tmp space, and snapStart reduces cold start times for Java functions by preloading initialization code.

Attach EFS for persistent storage

Workloads that need shared, persistent storage across invocations or functions can mount EFS file systems at a local path within the Lambda execution environment.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// EFS file system for Lambda
const example = new aws.efs.FileSystem("example", {
    encrypted: true,
    tags: {
        Name: "lambda-efs",
    },
});
const config = new pulumi.Config();
// List of subnet IDs for EFS mount targets
const subnetIds = config.getObject<Array<string>>("subnetIds") || [
    "subnet-12345678",
    "subnet-87654321",
];
// Mount target in each subnet
const exampleMountTarget: aws.efs.MountTarget[] = [];
for (const range = {value: 0}; range.value < subnetIds.length; range.value++) {
    exampleMountTarget.push(new aws.efs.MountTarget(`example-${range.value}`, {
        fileSystemId: example.id,
        subnetId: subnetIds[range.value],
        securityGroups: [efs.id],
    }));
}
// Access point for Lambda
const exampleAccessPoint = new aws.efs.AccessPoint("example", {
    fileSystemId: example.id,
    rootDirectory: {
        path: "/lambda",
        creationInfo: {
            ownerGid: 1000,
            ownerUid: 1000,
            permissions: "755",
        },
    },
    posixUser: {
        gid: 1000,
        uid: 1000,
    },
});
// Lambda function with EFS
const exampleFunction = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "example_efs_function",
    role: exampleAwsIamRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.NodeJS20dX,
    vpcConfig: {
        subnetIds: subnetIds,
        securityGroupIds: [lambda.id],
    },
    fileSystemConfig: {
        arn: exampleAccessPoint.arn,
        localMountPath: "/mnt/data",
    },
}, {
    dependsOn: [exampleMountTarget],
});
import pulumi
import pulumi_aws as aws

# EFS file system for Lambda
example = aws.efs.FileSystem("example",
    encrypted=True,
    tags={
        "Name": "lambda-efs",
    })
config = pulumi.Config()
# List of subnet IDs for EFS mount targets
subnet_ids = config.get_object("subnetIds")
if subnet_ids is None:
    subnet_ids = [
        "subnet-12345678",
        "subnet-87654321",
    ]
# Mount target in each subnet
example_mount_target = []
for range in [{"value": i} for i in range(0, len(subnet_ids))]:
    example_mount_target.append(aws.efs.MountTarget(f"example-{range['value']}",
        file_system_id=example.id,
        subnet_id=subnet_ids[range["value"]],
        security_groups=[efs["id"]]))
# Access point for Lambda
example_access_point = aws.efs.AccessPoint("example",
    file_system_id=example.id,
    root_directory={
        "path": "/lambda",
        "creation_info": {
            "owner_gid": 1000,
            "owner_uid": 1000,
            "permissions": "755",
        },
    },
    posix_user={
        "gid": 1000,
        "uid": 1000,
    })
# Lambda function with EFS
example_function = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="example_efs_function",
    role=example_aws_iam_role["arn"],
    handler="index.handler",
    runtime=aws.lambda_.Runtime.NODE_JS20D_X,
    vpc_config={
        "subnet_ids": subnet_ids,
        "security_group_ids": [lambda_["id"]],
    },
    file_system_config={
        "arn": example_access_point.arn,
        "local_mount_path": "/mnt/data",
    },
    opts = pulumi.ResourceOptions(depends_on=[example_mount_target]))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/efs"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// EFS file system for Lambda
		example, err := efs.NewFileSystem(ctx, "example", &efs.FileSystemArgs{
			Encrypted: pulumi.Bool(true),
			Tags: pulumi.StringMap{
				"Name": pulumi.String("lambda-efs"),
			},
		})
		if err != nil {
			return err
		}
		cfg := config.New(ctx, "")
		// List of subnet IDs for EFS mount targets
		subnetIds := []string{
			"subnet-12345678",
			"subnet-87654321",
		}
		if param := cfg.GetObject("subnetIds"); param != nil {
			subnetIds = param
		}
		// Mount target in each subnet
		var exampleMountTarget []*efs.MountTarget
		for index := 0; index < len(subnetIds); index++ {
			key0 := index
			val0 := index
			__res, err := efs.NewMountTarget(ctx, fmt.Sprintf("example-%v", key0), &efs.MountTargetArgs{
				FileSystemId: example.ID(),
				SubnetId:     pulumi.String(subnetIds[val0]),
				SecurityGroups: pulumi.StringArray{
					efs.Id,
				},
			})
			if err != nil {
				return err
			}
			exampleMountTarget = append(exampleMountTarget, __res)
		}
		// Access point for Lambda
		exampleAccessPoint, err := efs.NewAccessPoint(ctx, "example", &efs.AccessPointArgs{
			FileSystemId: example.ID(),
			RootDirectory: &efs.AccessPointRootDirectoryArgs{
				Path: pulumi.String("/lambda"),
				CreationInfo: &efs.AccessPointRootDirectoryCreationInfoArgs{
					OwnerGid:    pulumi.Int(1000),
					OwnerUid:    pulumi.Int(1000),
					Permissions: pulumi.String("755"),
				},
			},
			PosixUser: &efs.AccessPointPosixUserArgs{
				Gid: pulumi.Int(1000),
				Uid: pulumi.Int(1000),
			},
		})
		if err != nil {
			return err
		}
		// Lambda function with EFS
		_, err = lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:    pulumi.NewFileArchive("function.zip"),
			Name:    pulumi.String("example_efs_function"),
			Role:    pulumi.Any(exampleAwsIamRole.Arn),
			Handler: pulumi.String("index.handler"),
			Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
			VpcConfig: &lambda.FunctionVpcConfigArgs{
				SubnetIds: subnetIds,
				SecurityGroupIds: pulumi.StringArray{
					lambda.Id,
				},
			},
			FileSystemConfig: &lambda.FunctionFileSystemConfigArgs{
				Arn:            exampleAccessPoint.Arn,
				LocalMountPath: pulumi.String("/mnt/data"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			exampleMountTarget,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    // EFS file system for Lambda
    var example = new Aws.Efs.FileSystem("example", new()
    {
        Encrypted = true,
        Tags = 
        {
            { "Name", "lambda-efs" },
        },
    });

    var config = new Config();
    // List of subnet IDs for EFS mount targets
    var subnetIds = config.GetObject<string[]>("subnetIds") ?? new[]
    {
        "subnet-12345678",
        "subnet-87654321",
    };
    // Mount target in each subnet
    var exampleMountTarget = new List<Aws.Efs.MountTarget>();
    for (var rangeIndex = 0; rangeIndex < subnetIds.Length; rangeIndex++)
    {
        var range = new { Value = rangeIndex };
        exampleMountTarget.Add(new Aws.Efs.MountTarget($"example-{range.Value}", new()
        {
            FileSystemId = example.Id,
            SubnetId = subnetIds[range.Value],
            SecurityGroups = new[]
            {
                efs.Id,
            },
        }));
    }
    // Access point for Lambda
    var exampleAccessPoint = new Aws.Efs.AccessPoint("example", new()
    {
        FileSystemId = example.Id,
        RootDirectory = new Aws.Efs.Inputs.AccessPointRootDirectoryArgs
        {
            Path = "/lambda",
            CreationInfo = new Aws.Efs.Inputs.AccessPointRootDirectoryCreationInfoArgs
            {
                OwnerGid = 1000,
                OwnerUid = 1000,
                Permissions = "755",
            },
        },
        PosixUser = new Aws.Efs.Inputs.AccessPointPosixUserArgs
        {
            Gid = 1000,
            Uid = 1000,
        },
    });

    // Lambda function with EFS
    var exampleFunction = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "example_efs_function",
        Role = exampleAwsIamRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.NodeJS20dX,
        VpcConfig = new Aws.Lambda.Inputs.FunctionVpcConfigArgs
        {
            SubnetIds = subnetIds,
            SecurityGroupIds = new[]
            {
                lambda.Id,
            },
        },
        FileSystemConfig = new Aws.Lambda.Inputs.FunctionFileSystemConfigArgs
        {
            Arn = exampleAccessPoint.Arn,
            LocalMountPath = "/mnt/data",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            exampleMountTarget,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.efs.FileSystem;
import com.pulumi.aws.efs.FileSystemArgs;
import com.pulumi.aws.efs.MountTarget;
import com.pulumi.aws.efs.MountTargetArgs;
import com.pulumi.aws.efs.AccessPoint;
import com.pulumi.aws.efs.AccessPointArgs;
import com.pulumi.aws.efs.inputs.AccessPointRootDirectoryArgs;
import com.pulumi.aws.efs.inputs.AccessPointRootDirectoryCreationInfoArgs;
import com.pulumi.aws.efs.inputs.AccessPointPosixUserArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionVpcConfigArgs;
import com.pulumi.aws.lambda.inputs.FunctionFileSystemConfigArgs;
import com.pulumi.asset.FileArchive;
import com.pulumi.codegen.internal.KeyedValue;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var config = ctx.config();
        // EFS file system for Lambda
        var example = new FileSystem("example", FileSystemArgs.builder()
            .encrypted(true)
            .tags(Map.of("Name", "lambda-efs"))
            .build());

        final var subnetIds = config.get("subnetIds").orElse(        
            "subnet-12345678",
            "subnet-87654321");
        // Mount target in each subnet
        for (var i = 0; i < subnetIds.length(); i++) {
            new MountTarget("exampleMountTarget-" + i, MountTargetArgs.builder()
                .fileSystemId(example.id())
                .subnetId(subnetIds[range.value()])
                .securityGroups(efs.id())
                .build());

        
}
        // Access point for Lambda
        var exampleAccessPoint = new AccessPoint("exampleAccessPoint", AccessPointArgs.builder()
            .fileSystemId(example.id())
            .rootDirectory(AccessPointRootDirectoryArgs.builder()
                .path("/lambda")
                .creationInfo(AccessPointRootDirectoryCreationInfoArgs.builder()
                    .ownerGid(1000)
                    .ownerUid(1000)
                    .permissions("755")
                    .build())
                .build())
            .posixUser(AccessPointPosixUserArgs.builder()
                .gid(1000)
                .uid(1000)
                .build())
            .build());

        // Lambda function with EFS
        var exampleFunction = new Function("exampleFunction", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("example_efs_function")
            .role(exampleAwsIamRole.arn())
            .handler("index.handler")
            .runtime("nodejs20.x")
            .vpcConfig(FunctionVpcConfigArgs.builder()
                .subnetIds(subnetIds)
                .securityGroupIds(lambda.id())
                .build())
            .fileSystemConfig(FunctionFileSystemConfigArgs.builder()
                .arn(exampleAccessPoint.arn())
                .localMountPath("/mnt/data")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(exampleMountTarget)
                .build());

    }
}

The fileSystemConfig property mounts an EFS Access Point at the specified localMountPath. Your function code reads and writes files at /mnt/data as if it were local storage, but the data persists across invocations. The AccessPoint defines the POSIX user, path, and permissions. Mount targets in your VPC subnets connect Lambda to the file system. The function must use vpcConfig because EFS requires private network access.

Configure structured logging with JSON format

Production functions often use structured logs for better observability, filtering, and integration with log analysis tools.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.cloudwatch.LogGroup("example", {
    name: "/aws/lambda/example_function",
    retentionInDays: 14,
    tags: {
        Environment: "production",
        Application: "example",
    },
});
const exampleFunction = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "example_function",
    role: exampleAwsIamRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.NodeJS20dX,
    loggingConfig: {
        logFormat: "JSON",
        applicationLogLevel: "INFO",
        systemLogLevel: "WARN",
    },
}, {
    dependsOn: [example],
});
import pulumi
import pulumi_aws as aws

example = aws.cloudwatch.LogGroup("example",
    name="/aws/lambda/example_function",
    retention_in_days=14,
    tags={
        "Environment": "production",
        "Application": "example",
    })
example_function = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="example_function",
    role=example_aws_iam_role["arn"],
    handler="index.handler",
    runtime=aws.lambda_.Runtime.NODE_JS20D_X,
    logging_config={
        "log_format": "JSON",
        "application_log_level": "INFO",
        "system_log_level": "WARN",
    },
    opts = pulumi.ResourceOptions(depends_on=[example]))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := cloudwatch.NewLogGroup(ctx, "example", &cloudwatch.LogGroupArgs{
			Name:            pulumi.String("/aws/lambda/example_function"),
			RetentionInDays: pulumi.Int(14),
			Tags: pulumi.StringMap{
				"Environment": pulumi.String("production"),
				"Application": pulumi.String("example"),
			},
		})
		if err != nil {
			return err
		}
		_, err = lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:    pulumi.NewFileArchive("function.zip"),
			Name:    pulumi.String("example_function"),
			Role:    pulumi.Any(exampleAwsIamRole.Arn),
			Handler: pulumi.String("index.handler"),
			Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
			LoggingConfig: &lambda.FunctionLoggingConfigArgs{
				LogFormat:           pulumi.String("JSON"),
				ApplicationLogLevel: pulumi.String("INFO"),
				SystemLogLevel:      pulumi.String("WARN"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			example,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.CloudWatch.LogGroup("example", new()
    {
        Name = "/aws/lambda/example_function",
        RetentionInDays = 14,
        Tags = 
        {
            { "Environment", "production" },
            { "Application", "example" },
        },
    });

    var exampleFunction = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "example_function",
        Role = exampleAwsIamRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.NodeJS20dX,
        LoggingConfig = new Aws.Lambda.Inputs.FunctionLoggingConfigArgs
        {
            LogFormat = "JSON",
            ApplicationLogLevel = "INFO",
            SystemLogLevel = "WARN",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            example,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionLoggingConfigArgs;
import com.pulumi.asset.FileArchive;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new LogGroup("example", LogGroupArgs.builder()
            .name("/aws/lambda/example_function")
            .retentionInDays(14)
            .tags(Map.ofEntries(
                Map.entry("Environment", "production"),
                Map.entry("Application", "example")
            ))
            .build());

        var exampleFunction = new Function("exampleFunction", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("example_function")
            .role(exampleAwsIamRole.arn())
            .handler("index.handler")
            .runtime("nodejs20.x")
            .loggingConfig(FunctionLoggingConfigArgs.builder()
                .logFormat("JSON")
                .applicationLogLevel("INFO")
                .systemLogLevel("WARN")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(example)
                .build());

    }
}
resources:
  example:
    type: aws:cloudwatch:LogGroup
    properties:
      name: /aws/lambda/example_function
      retentionInDays: 14
      tags:
        Environment: production
        Application: example
  exampleFunction:
    type: aws:lambda:Function
    name: example
    properties:
      code:
        fn::FileArchive: function.zip
      name: example_function
      role: ${exampleAwsIamRole.arn}
      handler: index.handler
      runtime: nodejs20.x
      loggingConfig:
        logFormat: JSON
        applicationLogLevel: INFO
        systemLogLevel: WARN
    options:
      dependsOn:
        - ${example}

The loggingConfig property controls log format and verbosity. Setting logFormat to “JSON” structures logs as JSON objects rather than plain text, making them easier to parse and filter in CloudWatch Logs Insights. The applicationLogLevel controls your code’s log statements, while systemLogLevel controls Lambda’s internal logs. The LogGroup defines retention and tagging separately from the function.

Handle failures with dead letter queues and retries

Asynchronous invocations can fail due to transient errors or code issues. Dead letter queues capture failed events, and event invoke configuration controls retry behavior.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Main Lambda function
const example = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "example_function",
    role: exampleAwsIamRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.NodeJS20dX,
    deadLetterConfig: {
        targetArn: dlq.arn,
    },
});
// Event invoke configuration for retries
const exampleFunctionEventInvokeConfig = new aws.lambda.FunctionEventInvokeConfig("example", {
    functionName: example.name,
    maximumEventAgeInSeconds: 60,
    maximumRetryAttempts: 2,
    destinationConfig: {
        onFailure: {
            destination: dlq.arn,
        },
        onSuccess: {
            destination: success.arn,
        },
    },
});
import pulumi
import pulumi_aws as aws

# Main Lambda function
example = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="example_function",
    role=example_aws_iam_role["arn"],
    handler="index.handler",
    runtime=aws.lambda_.Runtime.NODE_JS20D_X,
    dead_letter_config={
        "target_arn": dlq["arn"],
    })
# Event invoke configuration for retries
example_function_event_invoke_config = aws.lambda_.FunctionEventInvokeConfig("example",
    function_name=example.name,
    maximum_event_age_in_seconds=60,
    maximum_retry_attempts=2,
    destination_config={
        "on_failure": {
            "destination": dlq["arn"],
        },
        "on_success": {
            "destination": success["arn"],
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// Main Lambda function
		example, err := lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:    pulumi.NewFileArchive("function.zip"),
			Name:    pulumi.String("example_function"),
			Role:    pulumi.Any(exampleAwsIamRole.Arn),
			Handler: pulumi.String("index.handler"),
			Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
			DeadLetterConfig: &lambda.FunctionDeadLetterConfigArgs{
				TargetArn: pulumi.Any(dlq.Arn),
			},
		})
		if err != nil {
			return err
		}
		// Event invoke configuration for retries
		_, err = lambda.NewFunctionEventInvokeConfig(ctx, "example", &lambda.FunctionEventInvokeConfigArgs{
			FunctionName:             example.Name,
			MaximumEventAgeInSeconds: pulumi.Int(60),
			MaximumRetryAttempts:     pulumi.Int(2),
			DestinationConfig: &lambda.FunctionEventInvokeConfigDestinationConfigArgs{
				OnFailure: &lambda.FunctionEventInvokeConfigDestinationConfigOnFailureArgs{
					Destination: pulumi.Any(dlq.Arn),
				},
				OnSuccess: &lambda.FunctionEventInvokeConfigDestinationConfigOnSuccessArgs{
					Destination: pulumi.Any(success.Arn),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    // Main Lambda function
    var example = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "example_function",
        Role = exampleAwsIamRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.NodeJS20dX,
        DeadLetterConfig = new Aws.Lambda.Inputs.FunctionDeadLetterConfigArgs
        {
            TargetArn = dlq.Arn,
        },
    });

    // Event invoke configuration for retries
    var exampleFunctionEventInvokeConfig = new Aws.Lambda.FunctionEventInvokeConfig("example", new()
    {
        FunctionName = example.Name,
        MaximumEventAgeInSeconds = 60,
        MaximumRetryAttempts = 2,
        DestinationConfig = new Aws.Lambda.Inputs.FunctionEventInvokeConfigDestinationConfigArgs
        {
            OnFailure = new Aws.Lambda.Inputs.FunctionEventInvokeConfigDestinationConfigOnFailureArgs
            {
                Destination = dlq.Arn,
            },
            OnSuccess = new Aws.Lambda.Inputs.FunctionEventInvokeConfigDestinationConfigOnSuccessArgs
            {
                Destination = success.Arn,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionDeadLetterConfigArgs;
import com.pulumi.aws.lambda.FunctionEventInvokeConfig;
import com.pulumi.aws.lambda.FunctionEventInvokeConfigArgs;
import com.pulumi.aws.lambda.inputs.FunctionEventInvokeConfigDestinationConfigArgs;
import com.pulumi.aws.lambda.inputs.FunctionEventInvokeConfigDestinationConfigOnFailureArgs;
import com.pulumi.aws.lambda.inputs.FunctionEventInvokeConfigDestinationConfigOnSuccessArgs;
import com.pulumi.asset.FileArchive;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        // Main Lambda function
        var example = new Function("example", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("example_function")
            .role(exampleAwsIamRole.arn())
            .handler("index.handler")
            .runtime("nodejs20.x")
            .deadLetterConfig(FunctionDeadLetterConfigArgs.builder()
                .targetArn(dlq.arn())
                .build())
            .build());

        // Event invoke configuration for retries
        var exampleFunctionEventInvokeConfig = new FunctionEventInvokeConfig("exampleFunctionEventInvokeConfig", FunctionEventInvokeConfigArgs.builder()
            .functionName(example.name())
            .maximumEventAgeInSeconds(60)
            .maximumRetryAttempts(2)
            .destinationConfig(FunctionEventInvokeConfigDestinationConfigArgs.builder()
                .onFailure(FunctionEventInvokeConfigDestinationConfigOnFailureArgs.builder()
                    .destination(dlq.arn())
                    .build())
                .onSuccess(FunctionEventInvokeConfigDestinationConfigOnSuccessArgs.builder()
                    .destination(success.arn())
                    .build())
                .build())
            .build());

    }
}
resources:
  # Main Lambda function
  example:
    type: aws:lambda:Function
    properties:
      code:
        fn::FileArchive: function.zip
      name: example_function
      role: ${exampleAwsIamRole.arn}
      handler: index.handler
      runtime: nodejs20.x
      deadLetterConfig:
        targetArn: ${dlq.arn}
  # Event invoke configuration for retries
  exampleFunctionEventInvokeConfig:
    type: aws:lambda:FunctionEventInvokeConfig
    name: example
    properties:
      functionName: ${example.name}
      maximumEventAgeInSeconds: 60
      maximumRetryAttempts: 2
      destinationConfig:
        onFailure:
          destination: ${dlq.arn}
        onSuccess:
          destination: ${success.arn}

When asynchronous invocations fail after all retries, Lambda sends the event to the dead letter queue specified in deadLetterConfig. The FunctionEventInvokeConfig resource controls retry behavior: maximumRetryAttempts sets how many times Lambda retries failed invocations (0-2), and maximumEventAgeInSeconds limits how long events stay in the queue. The destinationConfig routes successful and failed events to separate targets (SQS, SNS, Lambda, or EventBridge).

Grant CloudWatch Logs permissions to execution role

Lambda functions write logs to CloudWatch Logs automatically, but the execution role needs explicit permissions to create log groups and streams.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
// Name of the Lambda function
const functionName = config.get("functionName") || "example_function";
// CloudWatch Log Group with retention
const example = new aws.cloudwatch.LogGroup("example", {
    name: `/aws/lambda/${functionName}`,
    retentionInDays: 14,
    tags: {
        Environment: "production",
        Function: functionName,
    },
});
// Lambda execution role
const exampleRole = new aws.iam.Role("example", {
    name: "lambda_execution_role",
    assumeRolePolicy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Action: "sts:AssumeRole",
            Effect: "Allow",
            Principal: {
                Service: "lambda.amazonaws.com",
            },
        }],
    }),
});
// CloudWatch Logs policy
const lambdaLogging = new aws.iam.Policy("lambda_logging", {
    name: "lambda_logging",
    path: "/",
    description: "IAM policy for logging from Lambda",
    policy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Effect: "Allow",
            Action: [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
            ],
            Resource: ["arn:aws:logs:*:*:*"],
        }],
    }),
});
// Attach logging policy to Lambda role
const lambdaLogs = new aws.iam.RolePolicyAttachment("lambda_logs", {
    role: exampleRole.name,
    policyArn: lambdaLogging.arn,
});
// Lambda function with logging
const exampleFunction = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: functionName,
    role: exampleRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.NodeJS20dX,
    loggingConfig: {
        logFormat: "JSON",
        applicationLogLevel: "INFO",
        systemLogLevel: "WARN",
    },
}, {
    dependsOn: [
        lambdaLogs,
        example,
    ],
});
import pulumi
import json
import pulumi_aws as aws

config = pulumi.Config()
# Name of the Lambda function
function_name = config.get("functionName")
if function_name is None:
    function_name = "example_function"
# CloudWatch Log Group with retention
example = aws.cloudwatch.LogGroup("example",
    name=f"/aws/lambda/{function_name}",
    retention_in_days=14,
    tags={
        "Environment": "production",
        "Function": function_name,
    })
# Lambda execution role
example_role = aws.iam.Role("example",
    name="lambda_execution_role",
    assume_role_policy=json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com",
            },
        }],
    }))
# CloudWatch Logs policy
lambda_logging = aws.iam.Policy("lambda_logging",
    name="lambda_logging",
    path="/",
    description="IAM policy for logging from Lambda",
    policy=json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
            ],
            "Resource": ["arn:aws:logs:*:*:*"],
        }],
    }))
# Attach logging policy to Lambda role
lambda_logs = aws.iam.RolePolicyAttachment("lambda_logs",
    role=example_role.name,
    policy_arn=lambda_logging.arn)
# Lambda function with logging
example_function = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name=function_name,
    role=example_role.arn,
    handler="index.handler",
    runtime=aws.lambda_.Runtime.NODE_JS20D_X,
    logging_config={
        "log_format": "JSON",
        "application_log_level": "INFO",
        "system_log_level": "WARN",
    },
    opts = pulumi.ResourceOptions(depends_on=[
            lambda_logs,
            example,
        ]))
package main

import (
	"encoding/json"
	"fmt"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/cloudwatch"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		cfg := config.New(ctx, "")
		// Name of the Lambda function
		functionName := "example_function"
		if param := cfg.Get("functionName"); param != "" {
			functionName = param
		}
		// CloudWatch Log Group with retention
		example, err := cloudwatch.NewLogGroup(ctx, "example", &cloudwatch.LogGroupArgs{
			Name:            pulumi.Sprintf("/aws/lambda/%v", functionName),
			RetentionInDays: pulumi.Int(14),
			Tags: pulumi.StringMap{
				"Environment": pulumi.String("production"),
				"Function":    pulumi.String(functionName),
			},
		})
		if err != nil {
			return err
		}
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"Version": "2012-10-17",
			"Statement": []map[string]interface{}{
				map[string]interface{}{
					"Action": "sts:AssumeRole",
					"Effect": "Allow",
					"Principal": map[string]interface{}{
						"Service": "lambda.amazonaws.com",
					},
				},
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		// Lambda execution role
		exampleRole, err := iam.NewRole(ctx, "example", &iam.RoleArgs{
			Name:             pulumi.String("lambda_execution_role"),
			AssumeRolePolicy: pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		tmpJSON1, err := json.Marshal(map[string]interface{}{
			"Version": "2012-10-17",
			"Statement": []map[string]interface{}{
				map[string]interface{}{
					"Effect": "Allow",
					"Action": []string{
						"logs:CreateLogGroup",
						"logs:CreateLogStream",
						"logs:PutLogEvents",
					},
					"Resource": []string{
						"arn:aws:logs:*:*:*",
					},
				},
			},
		})
		if err != nil {
			return err
		}
		json1 := string(tmpJSON1)
		// CloudWatch Logs policy
		lambdaLogging, err := iam.NewPolicy(ctx, "lambda_logging", &iam.PolicyArgs{
			Name:        pulumi.String("lambda_logging"),
			Path:        pulumi.String("/"),
			Description: pulumi.String("IAM policy for logging from Lambda"),
			Policy:      pulumi.String(json1),
		})
		if err != nil {
			return err
		}
		// Attach logging policy to Lambda role
		lambdaLogs, err := iam.NewRolePolicyAttachment(ctx, "lambda_logs", &iam.RolePolicyAttachmentArgs{
			Role:      exampleRole.Name,
			PolicyArn: lambdaLogging.Arn,
		})
		if err != nil {
			return err
		}
		// Lambda function with logging
		_, err = lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
			Code:    pulumi.NewFileArchive("function.zip"),
			Name:    pulumi.String(functionName),
			Role:    exampleRole.Arn,
			Handler: pulumi.String("index.handler"),
			Runtime: pulumi.String(lambda.RuntimeNodeJS20dX),
			LoggingConfig: &lambda.FunctionLoggingConfigArgs{
				LogFormat:           pulumi.String("JSON"),
				ApplicationLogLevel: pulumi.String("INFO"),
				SystemLogLevel:      pulumi.String("WARN"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			lambdaLogs,
			example,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var config = new Config();
    // Name of the Lambda function
    var functionName = config.Get("functionName") ?? "example_function";
    // CloudWatch Log Group with retention
    var example = new Aws.CloudWatch.LogGroup("example", new()
    {
        Name = $"/aws/lambda/{functionName}",
        RetentionInDays = 14,
        Tags = 
        {
            { "Environment", "production" },
            { "Function", functionName },
        },
    });

    // Lambda execution role
    var exampleRole = new Aws.Iam.Role("example", new()
    {
        Name = "lambda_execution_role",
        AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Version"] = "2012-10-17",
            ["Statement"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Action"] = "sts:AssumeRole",
                    ["Effect"] = "Allow",
                    ["Principal"] = new Dictionary<string, object?>
                    {
                        ["Service"] = "lambda.amazonaws.com",
                    },
                },
            },
        }),
    });

    // CloudWatch Logs policy
    var lambdaLogging = new Aws.Iam.Policy("lambda_logging", new()
    {
        Name = "lambda_logging",
        Path = "/",
        Description = "IAM policy for logging from Lambda",
        PolicyDocument = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Version"] = "2012-10-17",
            ["Statement"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Effect"] = "Allow",
                    ["Action"] = new[]
                    {
                        "logs:CreateLogGroup",
                        "logs:CreateLogStream",
                        "logs:PutLogEvents",
                    },
                    ["Resource"] = new[]
                    {
                        "arn:aws:logs:*:*:*",
                    },
                },
            },
        }),
    });

    // Attach logging policy to Lambda role
    var lambdaLogs = new Aws.Iam.RolePolicyAttachment("lambda_logs", new()
    {
        Role = exampleRole.Name,
        PolicyArn = lambdaLogging.Arn,
    });

    // Lambda function with logging
    var exampleFunction = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = functionName,
        Role = exampleRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.NodeJS20dX,
        LoggingConfig = new Aws.Lambda.Inputs.FunctionLoggingConfigArgs
        {
            LogFormat = "JSON",
            ApplicationLogLevel = "INFO",
            SystemLogLevel = "WARN",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            lambdaLogs,
            example,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.cloudwatch.LogGroup;
import com.pulumi.aws.cloudwatch.LogGroupArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.iam.Policy;
import com.pulumi.aws.iam.PolicyArgs;
import com.pulumi.aws.iam.RolePolicyAttachment;
import com.pulumi.aws.iam.RolePolicyAttachmentArgs;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.inputs.FunctionLoggingConfigArgs;
import com.pulumi.asset.FileArchive;
import static com.pulumi.codegen.internal.Serialization.*;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var config = ctx.config();
        final var functionName = config.get("functionName").orElse("example_function");
        // CloudWatch Log Group with retention
        var example = new LogGroup("example", LogGroupArgs.builder()
            .name(String.format("/aws/lambda/%s", functionName))
            .retentionInDays(14)
            .tags(Map.ofEntries(
                Map.entry("Environment", "production"),
                Map.entry("Function", functionName)
            ))
            .build());

        // Lambda execution role
        var exampleRole = new Role("exampleRole", RoleArgs.builder()
            .name("lambda_execution_role")
            .assumeRolePolicy(serializeJson(
                jsonObject(
                    jsonProperty("Version", "2012-10-17"),
                    jsonProperty("Statement", jsonArray(jsonObject(
                        jsonProperty("Action", "sts:AssumeRole"),
                        jsonProperty("Effect", "Allow"),
                        jsonProperty("Principal", jsonObject(
                            jsonProperty("Service", "lambda.amazonaws.com")
                        ))
                    )))
                )))
            .build());

        // CloudWatch Logs policy
        var lambdaLogging = new Policy("lambdaLogging", PolicyArgs.builder()
            .name("lambda_logging")
            .path("/")
            .description("IAM policy for logging from Lambda")
            .policy(serializeJson(
                jsonObject(
                    jsonProperty("Version", "2012-10-17"),
                    jsonProperty("Statement", jsonArray(jsonObject(
                        jsonProperty("Effect", "Allow"),
                        jsonProperty("Action", jsonArray(
                            "logs:CreateLogGroup", 
                            "logs:CreateLogStream", 
                            "logs:PutLogEvents"
                        )),
                        jsonProperty("Resource", jsonArray("arn:aws:logs:*:*:*"))
                    )))
                )))
            .build());

        // Attach logging policy to Lambda role
        var lambdaLogs = new RolePolicyAttachment("lambdaLogs", RolePolicyAttachmentArgs.builder()
            .role(exampleRole.name())
            .policyArn(lambdaLogging.arn())
            .build());

        // Lambda function with logging
        var exampleFunction = new Function("exampleFunction", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name(functionName)
            .role(exampleRole.arn())
            .handler("index.handler")
            .runtime("nodejs20.x")
            .loggingConfig(FunctionLoggingConfigArgs.builder()
                .logFormat("JSON")
                .applicationLogLevel("INFO")
                .systemLogLevel("WARN")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    lambdaLogs,
                    example)
                .build());

    }
}
configuration:
  # Function name variable
  functionName:
    type: string
    default: example_function
resources:
  # CloudWatch Log Group with retention
  example:
    type: aws:cloudwatch:LogGroup
    properties:
      name: /aws/lambda/${functionName}
      retentionInDays: 14
      tags:
        Environment: production
        Function: ${functionName}
  # Lambda execution role
  exampleRole:
    type: aws:iam:Role
    name: example
    properties:
      name: lambda_execution_role
      assumeRolePolicy:
        fn::toJSON:
          Version: 2012-10-17
          Statement:
            - Action: sts:AssumeRole
              Effect: Allow
              Principal:
                Service: lambda.amazonaws.com
  # CloudWatch Logs policy
  lambdaLogging:
    type: aws:iam:Policy
    name: lambda_logging
    properties:
      name: lambda_logging
      path: /
      description: IAM policy for logging from Lambda
      policy:
        fn::toJSON:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource:
                - arn:aws:logs:*:*:*
  # Attach logging policy to Lambda role
  lambdaLogs:
    type: aws:iam:RolePolicyAttachment
    name: lambda_logs
    properties:
      role: ${exampleRole.name}
      policyArn: ${lambdaLogging.arn}
  # Lambda function with logging
  exampleFunction:
    type: aws:lambda:Function
    name: example
    properties:
      code:
        fn::FileArchive: function.zip
      name: ${functionName}
      role: ${exampleRole.arn}
      handler: index.handler
      runtime: nodejs20.x
      loggingConfig:
        logFormat: JSON
        applicationLogLevel: INFO
        systemLogLevel: WARN
    options:
      dependsOn:
        - ${lambdaLogs}
        - ${example}

The execution role’s assume role policy allows Lambda to use the role. The logging policy grants permissions to create log groups, streams, and write log events. Attaching the policy to the role via RolePolicyAttachment makes these permissions available when the function runs. The function’s loggingConfig specifies the log group name, format, and log levels. Without the logging policy, Lambda can’t write logs and invocations fail silently.

Beyond These Examples

These snippets focus on specific Lambda function features: Lambda Layers for code sharing, VPC networking and EFS mounts, structured logging and error handling, and IAM execution role configuration. They’re intentionally minimal rather than full serverless applications.

The examples may reference pre-existing infrastructure such as IAM execution roles (except Example 8 which shows role creation), VPC subnets and security groups, ECR repositories (for container images), and SQS queues or SNS topics (for dead letter configuration). They focus on configuring the function rather than provisioning everything around it.

To keep things focused, common Lambda patterns are omitted, including:

  • Container image deployment (imageUri, imageConfig)
  • Environment variables and KMS encryption (environment, kmsKeyArn)
  • Memory and timeout tuning (memorySize, timeout)
  • Concurrency controls (reservedConcurrentExecutions)
  • Function versioning and aliases (publish property)
  • Event source triggers (EventBridge, S3, API Gateway)
  • S3-based deployment packages (s3Bucket, s3Key)

These omissions are intentional: the goal is to illustrate how each Lambda feature is wired, not provide drop-in serverless modules. See the Lambda Function resource reference for all available configuration options.

Frequently Asked Questions

Deployment & Code Management
How do I deploy code to my Lambda function?
You have three mutually exclusive options: 1) Local file using code with FileArchive, 2) S3 bucket using s3Bucket and s3Key, or 3) Container image using imageUri pointing to an ECR repository. For larger deployment packages, Amazon recommends uploading via S3 since the S3 API has better support for large files.
What's required for container image deployments vs zip deployments?
For container images (packageType: "Image"), specify imageUri and optionally imageConfig. For zip deployments (packageType: "Zip", the default), you must specify handler and runtime along with one of the code deployment methods.
How does Lambda detect when I've updated my code?
Use the sourceCodeHash property with a base64-encoded SHA256 hash of your package file. When the hash changes, Lambda triggers an update. This is particularly useful for detecting changes in local files or S3 objects.
Common Errors & Troubleshooting
Why am I getting KMSAccessDeniedException when invoking my function?
This occurs when the IAM role associated with your function was deleted and recreated after the function was created. When you create a function, Lambda grants KMS permissions to the role; if the role is recreated, the grant becomes invalid. Fix it by updating the function’s role to a different role, then updating it back to the recreated role, or by recreating the function.
Why is deleting my VPC-enabled Lambda function taking so long?
VPC-enabled Lambda functions can take up to 45 minutes to delete due to Elastic Network Interface (ENI) cleanup. Pulumi AWS Provider version 2.31.0 and later automatically handles this timeout. For earlier versions, set deletion timeouts to 45 minutes (delete = "45m").
Networking & VPC
How do I connect my Lambda function to private VPC resources?
Configure vpcConfig with subnetIds and securityGroupIds. The function’s IAM role must have permissions to create and manage network interfaces (typically via the AWSLambdaVPCAccessExecutionRole managed policy).
What does replaceSecurityGroupsOnDestroy do?
When set to true, it replaces the security groups on the function’s VPC configuration before destruction. You must also provide replacementSecurityGroupIds with the list of replacement security group IDs. This defaults to false.
Resource Limits & Performance
What are the timeout and memory limits for Lambda functions?
Lambda functions default to 3 seconds timeout with a maximum of 900 seconds (15 minutes). Memory defaults to 128 MB with a range of 128 MB to 10,240 MB (10 GB) in 1 MB increments.
What does reservedConcurrentExecutions do?
This controls how many instances of your function can run concurrently. A value of 0 disables the function from being triggered, -1 (the default) removes any concurrency limitations, and positive values reserve that specific number of concurrent executions.
Permissions & Security
What's the difference between the role argument and aws.lambda.Permission?
The role argument is the function’s execution role, providing the function’s identity and access to AWS services and resources. Use aws.lambda.Permission to give external sources (like EventBridge, SNS, or S3) permission to invoke the Lambda function.
Advanced Features
How many Lambda layers can I attach to a function?
You can attach a maximum of 5 Lambda Layer Version ARNs to your function using the layers property. For Pulumi AWS Provider 2.x, use the layer’s arn attribute (the arn and layerArn attributes were swapped in version 2.0.0).
How do I attach an EFS file system to my Lambda function?
First create EFS mount targets in your VPC subnets, then configure fileSystemConfig with the access point ARN and localMountPath (e.g., “/mnt/data”). The function must have vpcConfig enabled and use dependsOn to ensure mount targets are created first.
How do I send Lambda logs to S3 or Data Firehose instead of CloudWatch?
Create a CloudWatch Log Group with logGroupClass: "DELIVERY" and a subscription filter pointing to your S3 bucket or Firehose stream. In your function’s loggingConfig, specify the log group name using logGroup. No special Lambda configuration is required beyond specifying the log group name.
Can I change my function's name or packageType after creation?
No, both name and packageType are immutable properties and cannot be changed after creation. You must create a new function to change these values.
How do I configure advanced logging with JSON format and log levels?
Use the loggingConfig block to set logFormat to “JSON” (or “Text”), then specify applicationLogLevel (e.g., “INFO”, “DEBUG”) and systemLogLevel (e.g., “WARN”, “ERROR”) to control the verbosity of application and Lambda system logs.

Ready to get started?

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Create free account