Layers & Shared Dependencies
A layer is a ZIP of code or dependencies that many functions can share instead of each bundling its own copy.
Busca en todas las páginas de la documentación
A layer is a ZIP of code or dependencies that many functions can share instead of each bundling its own copy.
Publishing a shared library, a set of third-party packages, or a common runtime dependency once - then attaching it to every function that needs it - keeps deployment packages small and updates consistent. This page shows how to publish a layer and wire it onto functions from both SDKs, plus the versioning and size rules that trip people up.
Publish the layer version, capture its ARN, then attach that ARN to the function's configuration.
# --- Python (boto3) ---
import boto3
lam = boto3.client("lambda")
with open("shared-deps.zip", "rb") as f:
layer = lam.publish_layer_version(
LayerName="shared-deps",
Content={"ZipFile": f.read()},
CompatibleRuntimes=["python3.12"],
CompatibleArchitectures=["x86_64"],
)
lam.update_function_configuration(
FunctionName="my-func",
Layers=[layer["LayerVersionArn"]],
)// --- TypeScript (AWS SDK v3) ---
import {
LambdaClient,
PublishLayerVersionCommand,
UpdateFunctionConfigurationCommand,
} from "@aws-sdk/client-lambda";
import { readFileSync } from "node:fs";
const lam = new LambdaClient({});
const layer = await lam.send(new PublishLayerVersionCommand({
LayerName: "shared-deps",
Content: { ZipFile: readFileSync("shared-deps.zip") },
CompatibleRuntimes: ["nodejs20.x"],
CompatibleArchitectures: ["x86_64"],
}));
await lam.send(new UpdateFunctionConfigurationCommand({
FunctionName: "my-func",
Layers: [layer.LayerVersionArn!],
}));When to reach for this:
/opt.A realistic flow: publish a layer from an artifact already staged in S3, attach it alongside an existing layer, and wait for the function to become active again.
# --- Python (boto3) ---
import boto3
lam = boto3.client("lambda")
layer = lam.publish_layer_version(
LayerName="data-utils",
Description="pandas + pyarrow, built for 3.12",
Content={"S3Bucket": "my-artifacts", "S3Key": "layers/data-utils-1.zip"},
CompatibleRuntimes=["python3.12"],
CompatibleArchitectures=["arm64"],
)
new_arn = layer["LayerVersionArn"]
# Keep an existing layer and add the new one (max 5 total).
current = lam.get_function_configuration(FunctionName="etl")
existing = [l["Arn"] for l in current.get("Layers", [])]
lam.update_function_configuration(FunctionName="etl", Layers=[*existing, new_arn])
lam.get_waiter("function_updated_v2").wait(FunctionName="etl")
print("attached", new_arn)// --- TypeScript (AWS SDK v3) ---
import {
LambdaClient,
PublishLayerVersionCommand,
GetFunctionConfigurationCommand,
UpdateFunctionConfigurationCommand,
waitUntilFunctionUpdatedV2,
} from "@aws-sdk/client-lambda";
const lam = new LambdaClient({});
const layer = await lam.send(new PublishLayerVersionCommand({
LayerName: "data-utils",
Description: "sharp image lib, built for 20.x",
Content: { S3Bucket: "my-artifacts", S3Key: "layers/data-utils-1.zip" },
CompatibleRuntimes: ["nodejs20.x"],
CompatibleArchitectures: ["arm64"],
}));
const newArn = layer.LayerVersionArn!;
const current = await lam.send(new GetFunctionConfigurationCommand({ FunctionName: "etl" }));
const existing = (current.Layers ?? []).map((l) => l.Arn!);
await lam.send(new UpdateFunctionConfigurationCommand({
FunctionName: "etl",
Layers: [...existing, newArn],
}));
await waitUntilFunctionUpdatedV2({ client: lam, maxWaitTime: 120 }, { FunctionName: "etl" });
console.log("attached", newArn);What this demonstrates:
S3Bucket/S3Key), avoiding the inline ZipFile request-size limit.Layers on UpdateFunctionConfiguration replaces the whole list, so you must re-include layers you want to keep.arm64 here) must match the function's architecture.When a function starts, Lambda extracts each attached layer into /opt in the execution environment, in the order you listed them. Later layers overlay earlier ones, so ordering matters if two layers ship the same path. The runtime already searches conventional subpaths under /opt, so a layer only "just works" if its ZIP uses the right internal structure:
python/ or python/lib/python3.12/site-packages/nodejs/node_modules/PATH: bin/PublishLayerVersion always creates a new numbered version and returns a LayerVersionArn ending in :<version>. You never mutate an existing version. To roll out an update, publish a new version and repoint functions at the new ARN; to roll back, repoint them at the old one. Because the ARN is version-pinned, a function's behavior does not change until you explicitly move it.
Old versions accumulate. Use list_layer_versions to enumerate and delete_layer_version to prune ones nothing references.
# --- Python (boto3) ---
import boto3
lam = boto3.client("lambda")
paginator = lam.get_paginator("list_layer_versions")
for page in paginator.paginate(LayerName="data-utils"):
for v in page["LayerVersions"]:
print(v["Version"], v["LayerVersionArn"])// --- TypeScript (AWS SDK v3) ---
import { LambdaClient, paginateListLayerVersions } from "@aws-sdk/client-lambda";
const lam = new LambdaClient({});
for await (const page of paginateListLayerVersions({ client: lam }, { LayerName: "data-utils" })) {
for (const v of page.LayerVersions ?? []) console.log(v.Version, v.LayerVersionArn);
}add_layer_version_permission grants another account (or the whole organization) permission to use a layer version. This is how a platform team publishes a base layer once and lets every account attach it.
Layers needs the full versioned ARN, not the layer name. Fix: use the LayerVersionArn returned by PublishLayerVersion.UpdateFunctionConfiguration replaces the whole Layers list. Fix: read the current config and re-include the ARNs you want to keep.python/ or nodejs/node_modules/. Fix: build the layer with the runtime's expected subpath.arm64 layer on an x86_64 function (or vice versa) fails. Fix: match CompatibleArchitectures to the function.| Alternative | Use When | Don't Use When |
|---|---|---|
| Layers | Many functions share the same deps and you want one update point | A single function has unique deps only it uses |
| Bundle deps in the package | Deps are function-specific or change with the code | Multiple functions duplicate the same large deps |
| Container image | Total artifact exceeds 250 MB or needs custom OS packages | A small ZIP-plus-layer already fits comfortably |
| S3-hosted asset loaded at runtime | Data or models fetched on demand, not code on the import path | You need the code available under /opt at import time |
Up to five. Their combined unzipped content, plus the function's own package, must stay under the 250 MB unzipped deployment limit.
By its full versioned ARN (ending in :<version>). That is the value PublishLayerVersion returns as LayerVersionArn, and it is what you put in the Layers list.
No. Each publish creates a new immutable version. To change a layer you publish a new version and repoint functions at it; the old version stays until you delete it.
Extracted into /opt in the execution environment. Use the runtime's conventional subpath (python/, nodejs/node_modules/, bin/) so imports and executables resolve automatically.
UpdateFunctionConfiguration replaces the entire Layers list. Read the current configuration, then send the existing ARNs plus the new one.
Yes. Grant access with add_layer_version_permission, specifying the account id or the whole organization. They then attach it by ARN like any other layer.
Repoint the function at the previous LayerVersionArn. Because layer versions are immutable, the old version is still there unless you deleted it.
Not inherently - layer content still has to be downloaded and extracted. The win is smaller, deduplicated packages and one update point, not faster starts on their own.
UpdateFunctionConfiguration call layers ride on.Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 23 jul 2026