ZIP or Containers? Deploying code to Lambda in 2025
When AWS Lambda launched in 2014, developers could only deploy their functions as ZIP files containing their code and dependencies. While there were some inconvenient quirks like folder structures and Lambda layers, ZIP files quickly became synonymous with Lambda development amongst developers.
At the same time, a new virtualization technology was making waves in the industry. Following its public debut in 2013, Docker revolutionized how developers package and ship applications by introducing a standardized way to bundle code, dependencies, and runtime environments into portable containers. The technology's ability to ensure consistent behavior across different environments resonated strongly with developers and operations teams alike, leading to rapid adoption across the industry.
Fast forward to December 2020, AWS Lambda expanded its capabilities by introducing Docker image support. This move bridged the gap between Docker's container-based development and serverless computing. Since then, developers were given a choice on how they deploy code on Lambda.
It is now 2025, and both deployment options remain viable choices for Lambda functions, each with its own set of advantages. The decision between ZIP files and container images has become increasingly nuanced, influenced by factors like team expertise, existing workflows, and specific application requirements. This raises an important question for development teams: which deployment method best serves their needs in today's cloud computing landscape?
In this post, we'll explore the key considerations that should guide your choice between ZIP and container image deployments for AWS Lambda. We'll examine each option and their PROs and CONs to help you make an informed decision for your serverless applications.
ZIP
ZIP deployment is the OG method for deploying Lambda functions. At its core, this method involves bundling your application code and dependencies into a compressed ZIP file and uploading it directly to AWS Lambda. This approach has stood the test of time, serving as the go-to method for Lambda for a long time.
When you use the ZIP method, you first organize your project files - your function code along with any dependencies - into the appropriate folder structure. You then compress these files into a ZIP package, ensuring all import paths are correctly maintained. This ZIP file can be uploaded to AWS Lambda either directly through the console, via the AWS CLI, or through higher-level CLI tools like AWS SAM. AWS Lambda will then unpack and run your code in its managed environment using the runtime you've specified.
When deploying with the ZIP method, you have two main options for managing dependencies. The first approach involves carefully structuring your project folders so your function code can import dependencies from a subfolder, then zipping everything together – though this can be tricky and prone to import errors at first. Alternatively, you can use Lambda layers, which allow you to package dependencies separately and attach them to multiple functions. While layers promote code reuse and smaller deployment packages, they introduce their own complexity: updating dependencies requires creating new layer versions and updating each function to use them, which can become cumbersome when managing multiple functions.
Pros
- Quick deployments. Once you get the hang of ZIP-ing up your project, the deployment process is fast. This allows for quick iterations. You can even use higher-level CLI tools like AWS SAM to package your code and deploy to AWS.
- The deployment process is (arguably) straightforward. This is especially the case if your team is not familiar with Docker. There are no technical overhead of building a Docker image, getting an image repository ready, etc.
Cons
- You have less control of the runtime environment. Yes, that is the whole point of serverless compute, but hear me out. You can run as many tests as you want on your local environment, but there is no guarantee that your code will also work on Lambda, because you are at the mercy of Lambda's runtime. Ideally, you want to test your code in an environment as close as your prod environment as possible, and Docker lets you do that.
- Requires developers to create a ZIP package, which is not a standard code deployment practice.
- If using Lambda layers, dependency management is complex.
Docker
Using Docker offers a different path to running Lambda functions by leveraging Docker's powerful containerization capabilities. Instead of managing ZIP files and layers separately, you can package your function code, dependencies, and runtime environment together in a single Docker image.
AWS provides official base images optimized for Lambda, which include the necessary runtime interface clients and tooling. Alternatively, for more specialized needs, you can even build custom images from scratch by incorporating the Lambda Runtime Interface Client, giving you complete control over your function's execution environment. For more info, check the AWS docs here.
One common concern about container image deployments has been their impact on cold start performance. Initially, Docker images did take a longer time to initialize compared to ZIP deployments, causing some teams to hesitate in using Docker.
However, AWS has made significant improvements to the container image startup process, particularly for larger environments. Recent benchmarks and real-world testing have shown that container-based functions now achieve comparable cold start times to their ZIP counterparts, effectively neutralizing what was once considered a major drawback of this deployment method. For more information on the recent performance increase for Docker images in Lambda, checkout these resources:
Pros
- Docker is now ubiquitous in the field of IT and software. It is the most used virtualization technology, and a lot of developers know how to write Dockerfiles and run Docker images.
- Easier to bundle up your environment for your code.
- Support code languages outside AWS Lambda's official list of supported languages using runtime clients
- Support a larger deployment package (ZIP is 250MB unzipped, Docker is 10GB).
- Test your code as if it were running in Lambda, using the Amazon Linux base image. Know that your code will run before you push your image.
Cons
- The deployment process is more involved. It will require you to write a Dockerfile, test your code in Docker, get an image repository ready, push your image to the repo, and then make sure Lambda can pull the image from your repo.
- You will probably want to build a proper CI/CD pipeline to make sure you can build, test, push and deploy your code, which is more overhead.
- In AWS's perspective, using Docker images is "less efficient". More than 80% of the bytes consisting each and every Docker image used in Lambda is not unique. This is because most Docker images use the same base image, so the portion of the image that contains your unique code is minuscule.
- This is why lazy-loading and caching is effective for Docker images.
In Conclusion
The decision between ZIP and container image deployments ultimately comes down to your specific use case and development workflow. For quick prototypes, internal tools, or simple test functions, the ZIP deployment method remains a perfectly valid choice, offering a faster feedback loop and a straightforward deployment.
However, for production workloads and team environments, container images are the more robust option. By using Docker, you gain the ability to build and test your functions locally, which improves your CI/CD pipelines with proper testing, and give you more control over your execution environment.
Concerns about cold start penalties with container images have been resolved, meaning you can now enjoy the improved developer experience and operational benefits of Docker without compromising on performance. Going into 2025, I strongly believe container images provide the most future-proof path forward for AWS Lambda.