Import libraries in lambda layers
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
AWS Lambda layers let you package shared dependencies separately from your function code, but importing libraries from a layer only works if the layer has the directory structure Lambda expects. For Python functions, the usual rule is simple: put the installed packages under a top-level python/ directory in the layer zip, attach the layer to the function, and then import the libraries normally in your handler.
The Expected Python Layer Structure
For Python runtimes, Lambda automatically adds the layer's python/ directory to the import path. That means a valid layer zip typically looks like this:
A practical build flow is:
After you publish the layer and attach it to a function, your function code can simply do:
There is no special import from layer syntax. If the layer is packaged correctly, normal imports work.
Publishing the Layer
Once the zip file is ready, publish it:
Then attach the resulting layer version ARN to your function in the console, CloudFormation, SAM, Terraform, or the CLI.
The important point is that a layer version is immutable. If dependencies change, publish a new layer version rather than modifying the old one in place.
Why Packaging Fails So Often
Most Lambda layer import failures are packaging problems, not Python import problems.
Common causes include:
- the zip does not contain a top-level
python/directory - packages were installed into the wrong folder
- the layer was built for the wrong Python version
- native dependencies were compiled on an incompatible operating system
If the layout is wrong, Lambda cannot discover the library on the runtime import path.
Native Dependencies Need Compatible Builds
Pure Python packages are the easy case. Native dependencies are stricter.
For example, a package with compiled extensions may work when zipped from your laptop and still fail in Lambda because the binary was built for macOS or Windows instead of the Linux environment Lambda actually runs.
In those cases, build the layer in an environment compatible with the target Lambda runtime, such as:
- Amazon Linux compatible build containers
- AWS SAM build workflows
- CI jobs that match the Lambda runtime architecture
This issue becomes even more important when CPU architecture matters, such as x86_64 versus arm64.
Keep Layers Focused
A layer should group dependencies that genuinely belong together. Good candidates are:
- shared HTTP libraries
- internal utility packages
- database clients reused across many functions
Bad candidates are giant "everything" layers that bundle unrelated dependencies for convenience. Those become hard to version, slow to build, and awkward to reuse.
If only one function uses a dependency, it may be simpler to package that dependency directly with the function instead of creating layer complexity.
Layer Versus Function Package
Layers are useful when:
- several functions share the same library set
- deployment size is easier to manage when dependencies are separated
- you want to update shared libraries independently of function code
Direct packaging is simpler when:
- only one function needs the dependency
- the dependency set changes often with the function
- the operational overhead of layer versioning is not worth it
The right choice is not always "use layers." It is "use layers when sharing and versioning actually help."
Troubleshooting Imports
If import requests fails even though the layer is attached, check these first:
- unzip the layer locally and verify the top-level
python/directory exists - confirm the package directory lives under that path
- verify the layer runtime matches the function runtime
- verify compiled dependencies were built for the Lambda target platform
A quick debugging trick is to inspect sys.path inside the function:
If the expected layer path is missing, the issue is attachment or packaging rather than the library itself.
Common Pitfalls
The biggest mistake is zipping the package contents directly without the top-level python/ directory. Lambda will not place those files on the expected Python import path.
Another issue is building dependencies on a machine whose OS or architecture does not match the Lambda runtime, which breaks native extensions.
Developers also often treat layers as a universal best practice. If a dependency is function-specific and changes constantly, direct packaging may be simpler.
Finally, remember that attaching the wrong layer version is effectively the same as attaching the wrong dependency set. Layer versions are explicit, so check the ARN carefully.
Summary
- For Python Lambda layers, package dependencies under a top-level
python/directory. - Publish the layer, attach it to the function, and import the library normally in code.
- Most import failures come from incorrect zip structure or incompatible native builds.
- Build native dependencies for the actual Lambda runtime environment.
- Use layers when shared dependencies and independent versioning are worth the extra operational complexity.
Related reading
- ImportError cannot import name 'docevents' from 'botocore.docs.bcdoc' in AWS CodeBuild
- In AWS - difference between Immutable and Blue/Green deployments?
- In AWS IAM, What is the Purpose/Use of the Path Variable?
- In AWS Lambda, where can I securely store API Credentials?
- IN statement in dynamodb
- In Terraform, how do you specify an API Gateway endpoint with a variable in the request path?
- Inconsistent cache values using Zend Cache with AWS ElastiCache across multiple servers
- Incorporate existing AWS resources into a CloudFormation stack

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.