Create AWS Lambda Layer Versions

The aws:lambda/layerVersion:LayerVersion resource, part of the Pulumi AWS provider, defines a Lambda Layer version: its code package, compatible runtimes and architectures, and metadata. This guide focuses on three capabilities: local and S3-based deployment, runtime and architecture compatibility, and metadata and version management.

Lambda Layers are standalone resources that functions reference to share code and dependencies. S3-based layers require existing S3 objects containing the layer ZIP. The examples are intentionally small. Combine them with your own Lambda functions and permission policies.

Deploy a layer from a local ZIP file

Most deployments package shared code into a ZIP and specify which runtimes can use it.

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

const example = new aws.lambda.LayerVersion("example", {
    code: new pulumi.asset.FileArchive("lambda_layer_payload.zip"),
    layerName: "lambda_layer_name",
    compatibleRuntimes: ["nodejs20.x"],
});
import pulumi
import pulumi_aws as aws

example = aws.lambda_.LayerVersion("example",
    code=pulumi.FileArchive("lambda_layer_payload.zip"),
    layer_name="lambda_layer_name",
    compatible_runtimes=["nodejs20.x"])
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.NewLayerVersion(ctx, "example", &lambda.LayerVersionArgs{
			Code:      pulumi.NewFileArchive("lambda_layer_payload.zip"),
			LayerName: pulumi.String("lambda_layer_name"),
			CompatibleRuntimes: pulumi.StringArray{
				pulumi.String("nodejs20.x"),
			},
		})
		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.LayerVersion("example", new()
    {
        Code = new FileArchive("lambda_layer_payload.zip"),
        LayerName = "lambda_layer_name",
        CompatibleRuntimes = new[]
        {
            "nodejs20.x",
        },
    });

});
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.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 LayerVersion("example", LayerVersionArgs.builder()
            .code(new FileArchive("lambda_layer_payload.zip"))
            .layerName("lambda_layer_name")
            .compatibleRuntimes("nodejs20.x")
            .build());

    }
}
resources:
  example:
    type: aws:lambda:LayerVersion
    properties:
      code:
        fn::FileArchive: lambda_layer_payload.zip
      layerName: lambda_layer_name
      compatibleRuntimes:
        - nodejs20.x

The code property points to your local ZIP file. The compatibleRuntimes property lists which Lambda runtimes can attach this layer. Each deployment creates a new immutable layer version that functions reference by ARN.

Deploy a layer from S3 with multiple runtimes

For larger packages or CI/CD workflows, teams upload layer ZIPs to S3 and reference them by bucket and key.

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

const example = new aws.lambda.LayerVersion("example", {
    s3Bucket: lambdaLayerZip.bucket,
    s3Key: lambdaLayerZip.key,
    layerName: "lambda_layer_name",
    compatibleRuntimes: [
        "nodejs20.x",
        "python3.12",
    ],
    compatibleArchitectures: [
        "x86_64",
        "arm64",
    ],
});
import pulumi
import pulumi_aws as aws

example = aws.lambda_.LayerVersion("example",
    s3_bucket=lambda_layer_zip["bucket"],
    s3_key=lambda_layer_zip["key"],
    layer_name="lambda_layer_name",
    compatible_runtimes=[
        "nodejs20.x",
        "python3.12",
    ],
    compatible_architectures=[
        "x86_64",
        "arm64",
    ])
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.NewLayerVersion(ctx, "example", &lambda.LayerVersionArgs{
			S3Bucket:  pulumi.Any(lambdaLayerZip.Bucket),
			S3Key:     pulumi.Any(lambdaLayerZip.Key),
			LayerName: pulumi.String("lambda_layer_name"),
			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
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Lambda.LayerVersion("example", new()
    {
        S3Bucket = lambdaLayerZip.Bucket,
        S3Key = lambdaLayerZip.Key,
        LayerName = "lambda_layer_name",
        CompatibleRuntimes = new[]
        {
            "nodejs20.x",
            "python3.12",
        },
        CompatibleArchitectures = new[]
        {
            "x86_64",
            "arm64",
        },
    });

});
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 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 LayerVersion("example", LayerVersionArgs.builder()
            .s3Bucket(lambdaLayerZip.bucket())
            .s3Key(lambdaLayerZip.key())
            .layerName("lambda_layer_name")
            .compatibleRuntimes(            
                "nodejs20.x",
                "python3.12")
            .compatibleArchitectures(            
                "x86_64",
                "arm64")
            .build());

    }
}
resources:
  example:
    type: aws:lambda:LayerVersion
    properties:
      s3Bucket: ${lambdaLayerZip.bucket}
      s3Key: ${lambdaLayerZip.key}
      layerName: lambda_layer_name
      compatibleRuntimes:
        - nodejs20.x
        - python3.12
      compatibleArchitectures:
        - x86_64
        - arm64

The s3Bucket and s3Key properties replace the code property for S3-based deployment. The compatibleRuntimes and compatibleArchitectures properties let you support multiple languages and CPU architectures in a single layer. AWS recommends S3 for packages larger than a few megabytes.

Add metadata and change detection to layer versions

Production layers benefit from descriptive metadata and automatic versioning when code changes.

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

const example = new aws.lambda.LayerVersion("example", {
    code: new pulumi.asset.FileArchive("lambda_layer_payload.zip"),
    layerName: "multi_runtime_layer",
    description: "Shared utilities for Lambda functions",
    licenseInfo: "MIT",
    sourceCodeHash: std.filebase64sha256({
        input: "lambda_layer_payload.zip",
    }).then(invoke => invoke.result),
    compatibleRuntimes: [
        "nodejs18.x",
        "nodejs20.x",
        "python3.11",
        "python3.12",
    ],
    compatibleArchitectures: [
        "x86_64",
        "arm64",
    ],
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

example = aws.lambda_.LayerVersion("example",
    code=pulumi.FileArchive("lambda_layer_payload.zip"),
    layer_name="multi_runtime_layer",
    description="Shared utilities for Lambda functions",
    license_info="MIT",
    source_code_hash=std.filebase64sha256(input="lambda_layer_payload.zip").result,
    compatible_runtimes=[
        "nodejs18.x",
        "nodejs20.x",
        "python3.11",
        "python3.12",
    ],
    compatible_architectures=[
        "x86_64",
        "arm64",
    ])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeFilebase64sha256, err := std.Filebase64sha256(ctx, &std.Filebase64sha256Args{
			Input: "lambda_layer_payload.zip",
		}, nil)
		if err != nil {
			return err
		}
		_, err = lambda.NewLayerVersion(ctx, "example", &lambda.LayerVersionArgs{
			Code:           pulumi.NewFileArchive("lambda_layer_payload.zip"),
			LayerName:      pulumi.String("multi_runtime_layer"),
			Description:    pulumi.String("Shared utilities for Lambda functions"),
			LicenseInfo:    pulumi.String("MIT"),
			SourceCodeHash: pulumi.String(invokeFilebase64sha256.Result),
			CompatibleRuntimes: pulumi.StringArray{
				pulumi.String("nodejs18.x"),
				pulumi.String("nodejs20.x"),
				pulumi.String("python3.11"),
				pulumi.String("python3.12"),
			},
			CompatibleArchitectures: pulumi.StringArray{
				pulumi.String("x86_64"),
				pulumi.String("arm64"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Lambda.LayerVersion("example", new()
    {
        Code = new FileArchive("lambda_layer_payload.zip"),
        LayerName = "multi_runtime_layer",
        Description = "Shared utilities for Lambda functions",
        LicenseInfo = "MIT",
        SourceCodeHash = Std.Filebase64sha256.Invoke(new()
        {
            Input = "lambda_layer_payload.zip",
        }).Apply(invoke => invoke.Result),
        CompatibleRuntimes = new[]
        {
            "nodejs18.x",
            "nodejs20.x",
            "python3.11",
            "python3.12",
        },
        CompatibleArchitectures = new[]
        {
            "x86_64",
            "arm64",
        },
    });

});
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.std.StdFunctions;
import com.pulumi.std.inputs.Filebase64sha256Args;
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 LayerVersion("example", LayerVersionArgs.builder()
            .code(new FileArchive("lambda_layer_payload.zip"))
            .layerName("multi_runtime_layer")
            .description("Shared utilities for Lambda functions")
            .licenseInfo("MIT")
            .sourceCodeHash(StdFunctions.filebase64sha256(Filebase64sha256Args.builder()
                .input("lambda_layer_payload.zip")
                .build()).result())
            .compatibleRuntimes(            
                "nodejs18.x",
                "nodejs20.x",
                "python3.11",
                "python3.12")
            .compatibleArchitectures(            
                "x86_64",
                "arm64")
            .build());

    }
}
resources:
  example:
    type: aws:lambda:LayerVersion
    properties:
      code:
        fn::FileArchive: lambda_layer_payload.zip
      layerName: multi_runtime_layer
      description: Shared utilities for Lambda functions
      licenseInfo: MIT
      sourceCodeHash:
        fn::invoke:
          function: std:filebase64sha256
          arguments:
            input: lambda_layer_payload.zip
          return: result
      compatibleRuntimes:
        - nodejs18.x
        - nodejs20.x
        - python3.11
        - python3.12
      compatibleArchitectures:
        - x86_64
        - arm64

The description and licenseInfo properties document what the layer contains and its licensing terms. The sourceCodeHash property triggers new layer version creation when the ZIP content changes. Without sourceCodeHash, Pulumi won’t detect code changes and won’t create new versions.

Beyond these examples

These snippets focus on specific layer version features: local and S3-based deployment, runtime and architecture compatibility, and metadata and version management. They’re intentionally minimal rather than full sharing solutions.

The examples may reference pre-existing infrastructure such as S3 buckets with layer ZIP files for S3-based deployment. They focus on configuring the layer version rather than provisioning storage or permissions.

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

  • Version retention (skipDestroy property)
  • Layer permissions (aws.lambda.LayerVersionPermission resource)
  • Cross-account sharing and organization access
  • Code signing (signingJobArn, signingProfileVersionArn)

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

Let's create AWS Lambda Layer Versions

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Deployment & Code Management
What are my options for deploying layer code?
You can deploy using either a local file with the code property (e.g., new pulumi.asset.FileArchive("file.zip")) or from S3 using s3Bucket, s3Key, and optionally s3ObjectVersion. These options are mutually exclusive. For larger deployment packages, S3 is recommended because the S3 API has better support for uploading large files efficiently.
What's sourceCodeHash and why is it required?
sourceCodeHash is a required, immutable property that triggers layer replacement when source code changes. It must be a base64-encoded SHA256 hash of your package file. Use filebase64sha256("file.zip") or base64sha256(file("file.zip")) to generate it.
Can I use an S3 bucket in a different region?
No, the S3 bucket must reside in the same AWS region where you’re creating the Lambda layer.
Versioning & Lifecycle
What happens when I change layer properties like description or runtimes?
When skipDestroy is false (the default), changing properties like compatibleArchitectures, compatibleRuntimes, description, layerName, licenseInfo, or sourceCodeHash forces deletion of the existing layer version and creation of a new one.
What does skipDestroy do and when should I use it?
Setting skipDestroy to true prevents Pulumi from destroying layer versions, even when running pulumi destroy. This creates intentional dangling resources that remain in AWS and may incur extra storage costs. Only use this when you need to retain old layer versions permanently.
How can I update my layer without deleting the old version?
Set skipDestroy: true to preserve old versions when updating layer configuration. Otherwise, the default behavior (skipDestroy: false) deletes the existing version when you change most properties.
Compatibility & Limits
How many runtimes can I specify for a layer?
You can specify up to 15 runtimes in the compatibleRuntimes property.
What architectures can Lambda layers support?
Lambda layers can specify x86_64 and arm64 in the compatibleArchitectures property.
Can I make a layer compatible with both Node.js and Python?
Yes, you can specify multiple runtimes in compatibleRuntimes, such as ["nodejs20.x", "python3.12"], as shown in the S3 source example.
Resource Management
What properties are immutable after creation?
The following properties are immutable: layerName, sourceCodeHash, code, compatibleArchitectures, compatibleRuntimes, description, licenseInfo, s3Bucket, s3Key, s3ObjectVersion, and skipDestroy. Changing these forces replacement when skipDestroy is false.

Using a different cloud?

Explore serverless guides for other cloud providers: