With AWS Lambda, deploying a new version of our application has never been simpler. However, we still need to take care of some underlying plumbing. Such as managing the configuration for our functions as well as other related resources such as API Gateway, CloudWatch log groups and IAM policies. Depending on the event sources you would like to use, you also need to provision the necessary EventSourceMapping in order to use Lambda with the likes of Kinesis Streams and SQS.
If you configure everything by hand the AWS console handles all these complexities for you. But as engineers who embrace the DevOps values of automation and repeatable builds, we want to follow Infrastructure as Code (IaC) as well. And we also want to work with a layer of abstraction that shields us from these incidental complexities related to CloudFormation and Lambda. This is where deployment frameworks come in.
In this post, let’s look at some of the popular deployment frameworks for Lambda. As a way of comparison, we will focus the discussion on where each framework lands on:
The Serverless framework is one of the most popular and mature frameworks out there. Currently at v1.36.3, the next main version update has been in the works for some time too. It has benefited from a lot of user feedback based on production usage, and the size of its community is its greatest advantage.
The Serverless framework is general purpose and provides a layer of abstraction on top of CloudFormation. You configure your functions and other related AWS resources in a serverless.yml file, which is then compiled to CloudFormation and deployed as a CloudFormation stack.
It gives you a lot of control over the CloudFormation template, and the plugin system lets you extend the behavior of the framework in all kinds of interesting ways. Indeed, technically the whole framework is one big plugin system. The AWS support itself is built as a plugin, as are all the other providers it supports – Azure, GCP, IBM OpenWhisk, CloudFlare, Kubeless, Fn and Spotinst. It also has a number of useful built-in commands such as the ability to execute functions locally and to tail function logs from the CLI. There is a large ecosystem of available plugins thanks to the strength and size of its community.
While it is very customizable, it also has strong opinions in certain places. For example, it has a set of naming conventions (that can be tailored via plugins) and insists on using a separate API Gateway for each stage.
Serverless Application Model, or SAM, is the official deployment framework from AWS. Like the Serverless framework, it too is built on top of CloudFormation. You configure your functions and other related AWS resources in a template.yml file, which is then translated to CloudFormation and deployed as a CloudFormation stack.
Terraform is by far the least opinionated framework on this list. True to its motto of “Write, Plan, and Create Infrastructure as Code”, Terraform has long been favoured by infrastructure engineers and is not designed with Lambda as its focus. Instead, it treats Lambda functions as AWS resources, nothing more, nothing less.
As such, you have the utmost control and can configure Lambda and API Gateway, and any other resources however you like. However, this does expose you to all the underlying complexities. For example, you need to understand how API Gateway resources are organized, which I find to be one of the most laborious aspects of using Terraform for Lambda. A single line of human readable URL in the Serverless framework or SAM can easily translate to 50 lines of Terraform code.
Since Terraform is designed to give you a way to describe and create your infrastructure, it doesn’t offer any value-add services for Lambda either. There’s no built-in support for packaging your deployment artifact, nor is there any built-in support for running functions locally.
Unlike the frameworks we have seen so far, Claudia.js takes an opinionated approach and is designed with specific use cases in mind. Claudia.js makes it very easy to build and deploy a Node.js web application that runs on Lambda and API Gateway.
Chalice is a framework from AWS for writing serverless applications in Python. Chalice makes it easy to build REST APIs using Flask-like URL routing. It also comes with a CLI tool that offers some useful commands such as generating IAM policies and running API Gateway locally.
Zappa is probably the most popular framework for Python. Zappa makes it easy to take an existing Flask or Django app and deploy it to Lambda and API Gateway. It provides an easy path to lift-and-shift existing solutions to serverless.
Personally I am dubious of this approach. On one hand I think it’s great that there is an easy adoption path for folks who want to reap the benefits of serverless in terms of scalability and not paying for idle. On the other hand, I have too often seen these projects run into trouble because they were never designed with Lambda in mind. The fact that so much is abstracted away means the developers didn’t need to understand the platform their application runs on. As such, they often struggle to deal with performance and cost issues when they arise.
Apex is the first of two frameworks on this list by TJ Holowaychuk. If you have been using Node.js then you probably knows TJ or have used one of his libraries already. In fact, Apex provided a lot of inspiration for the first version of the Serverless framework.
One of the key features of Apex is the ability to support language runtimes that were not natively supported. It achieved this through the use of Node.js shims that are injected into the build process. However, the announcement of Lambda custom runtimes has effectively made this feature obsolete.
Up is the second framework from TJ Holowaychuk. Compared to Apex, Up has added a whole bunch of new features, including support for multiple providers and built-in middlewares.
One interesting capability Up offers, is the ability to separate the planning and the application of configuration changes. You can see what configuration changes Up will apply by running the `up stack plan` command. Once you are satisfied with the plan, then you must run the `up stack apply` command to actually apply the changes. This is similar to the `terraform plan` and `terraform apply` commands for those of you who are familiar with Terraform.
Like some of the other tools in this list, Up also has the ability to run an API Gateway locally with the `up start` command too.
Architect is a very opinionated framework, and a very productive one if its opinions align with yours and its choices make sense to your workload. Everything Architect does follows this philosophy. From simple things such as enforcing conventions on how you structure your project. To the “batteries-included” approach of shipping an auto-generated data access layer for DynamoDB tables.
So that’s it, a whirlwind tour of nine popular deployment frameworks for Lambda. I’m sure I have not done every framework justice with my assessment. I simply do not have enough experience with all of them to give a balanced overview for them all, but I hope you still find the information in this post useful.
In terms of features, all the frameworks fulfill the basic requirement of packaging and deploying your code to Lambda very well. Some have value-add features such as invoking functions locally or even running API Gateway locally too. While these features are all useful, I find most of the time I am able to live without them. Instead, the things that have a more telling impact are:
After categorizing these into customizability and opinionatedness, here is how I see these frameworks line up along these two axis.
Got opinions? Let us know your deployment framework of choice – and why – on Twitter.