Lambda Layers let you package dependencies separately from your function code, making your deployment packages smaller and your code easier to manage.

Here’s a quick look at how it works in action. Imagine you have a Python function that uses the requests library. Instead of including requests in every function’s deployment package, you can put it in a Lambda Layer.

{
  "FunctionName": "my-python-function",
  "Layers": [
    "arn:aws:lambda:us-east-1:123456789012:layer:my-requests-layer:1"
  ],
  "Runtime": "python3.9",
  "Handler": "index.handler",
  "Code": {
    "S3Bucket": "my-function-code-bucket",
    "S3Key": "my-python-function.zip"
  }
}

In your function code (index.py), you’d just import requests as usual:

import requests

def handler(event, context):
    response = requests.get("https://www.example.com")
    return {
        "statusCode": 200,
        "body": f"Request to example.com returned status: {response.status_code}"
    }

The Lambda runtime automatically makes the libraries in your layer available in the /opt directory. So, when your function runs, it finds requests in /opt/python/lib/python3.9/site-packages/requests.

This solves a few common problems. First, it dramatically reduces the size of your individual Lambda function deployment packages. If you have many functions sharing the same large libraries (like pandas, numpy, or even entire SDKs), each function’s zip file can grow very large. By externalizing these dependencies into layers, you can keep your function code lean, often under the 50MB unzipped limit, and even under the 250MB zipped limit for direct uploads. This also speeds up deployment times and reduces the chances of hitting deployment package size limits.

Second, it simplifies dependency management. Instead of updating a library in dozens or hundreds of individual function codebases, you update it once in the layer. This ensures consistency across your functions and makes patching security vulnerabilities much more efficient. When you update a layer, all functions using that layer automatically pick up the new version on their next invocation (provided the version number is incremented).

Internally, a Lambda Layer is essentially a zip archive that contains libraries, custom runtimes, or other dependencies. When you create a layer, you specify the compatible runtimes and architecture. AWS then makes the contents of the layer available to your Lambda function’s execution environment. For Python, the standard directory structure is python/lib/pythonX.Y/site-packages/, where X.Y is your Python runtime version (e.g., python3.9). For Node.js, it’s typically nodejs/node_modules/. Other runtimes have their own conventions, often mapping to /opt.

The Layers configuration in your function’s settings is an array of layer ARNs. You can specify multiple layers, and they are applied in the order they appear in the array. The runtime then merges these layers with the function’s own code, with later layers potentially overwriting earlier ones if there are naming conflicts. The content of each layer is extracted into /opt/<layer_content_directory_name> within the execution environment.

One crucial detail that often trips people up is how versioning works and the implications for immutability. When you publish a new version of a layer, it gets a new ARN. Functions configured to use a specific layer ARN will not automatically update to the new version. You must explicitly update the function’s configuration to point to the new layer ARN. This design provides stability: if a new layer version introduces a breaking change, your existing functions continue to run with the old, stable version until you’re ready to update them. However, it also means that to roll out an update to all functions, you need to iterate through each function’s configuration.

The next logical step is understanding how to manage layer versions and the impact of layer execution order on your code.

Want structured learning?

Take the full Lambda course →