Serverless Framework vs CDK, Which One Should I Use?
The Serverless Framework and the AWS Cloud Development Kit (CDK) are two popular frameworks for building out Amazon Web Services infrastructure through locally-stored code. We’ll take a look at the advantages of each one and see which you might want to use in your next AWS project.
What is Serverless?
The Serverless Framework is a configuration-based framework that lets you define serverless applications for multiple cloud platforms, such as AWS, Azure, and Google Cloud Platform. The Open Source version of Serverless is open sourced under the MIT license, and offers everything needed for creating serverless applications. There’s also a proprietary Pro version, which offers extra features to improve things like CI/CD and lifecycle management for serverless applications.
Serverless configuration can be managed either through YAML or JSON files. For more dynamic and flexible configuration, JavaScript can be used to support these needs.
For AWS, Serverless takes your configuration and turns it into a CloudFormation stack with your Lambda functions and other AWS resources.
What is the CDK?
The AWS CDK (short for “Cloud Development Kit”) is a code-based framework that lets you define AWS resources declaratively, through code. CDK is developed by the AWS team itself, and is open sourced under the Apache License 2.0. CDK supports a few different programming languages, including JavaScript, TypeScript, Python, Java, and C#. Support for more languages is also planned.
With CDK, you’ll write typical code in whichever supported language you’ve chosen, with minimal usage of config files.
Similarly to Serverless, CDK takes your code and converts it into a CloudFormation stack to build out your AWS infrastructure.
Where Serverless Is Useful
Usually you’ll use Serverless if your focus is on Lambda functions — stateless functions whose underlying resources are automatically managed by AWS based on how heavily they’re being utilized. With Serverless, you write your functions in any of the languages supported by AWS Lambda (Java, Go, PowerShell, Node.js, C#, Python, and Ruby at the time of this post), then you reference them inside your serverless configuration file. You can also specify any other resources you want, such as an RDS database in a resources section of the config file, using CloudFormation syntax (with some extra features that Serverless provides for more dynamic configuration). Below is an example of what your serverless.yml file might look like for a simple function. This function has an EventBridge rule to run the Lambda automatically at set intervals and access to an S3 bucket for the Lambda.
When you deploy, Serverless will push your code out to AWS and set up the CloudFormation infrastructure for you. As you can see, Serverless makes it pretty simple to deploy Lambda functions.
If you’re using JavaScript or TypeScript for your Lambdas, Serverless also has a plugin you can use if you’d like to bundle your Lambdas with Webpack, called serverless-webpack.
Where Serverless Falls Flat
You might have noticed that while it’s really easy to define Lambda functions with Serverless, defining other resources just boils down to writing CloudFormation. This can get complex and unwieldy pretty quickly. For example, take a look at the configuration below. You might find this in the resources section of a serverless.yml file. It defines a simple CloudFront distribution, but it’s very long and complex. Configurations like this can get difficult to manage pretty quickly.
On top of this, the number of resources you can have per AWS CloudFormation stack is a hard limit of 200. Each Lambda made with Serverless can generate up to 6 CloudFormation resources, and that’s in addition to any other resources you might want to include. That adds up fast, and Serverless doesn’t have a built-in way to work around the limit. There are a few options you can try, such as the ones detailed in this article. For example, there are some plugins available, such as serverless-nested-stack, but these come with their own limitations. You can also try managing multiple stacks yourself and sharing the resources in a single “base” stack, but this can also become cumbersome rather quickly.
Serverless is also very heavily focused around AWS Lambda in AWS. If you’re trying to put together something else with it, you’re going to have to define the CloudFormation yourself in the resources section, or find a plugin to accomplish your desired task.
What’s So Special About CDK?
CDK really shines when it comes to building out bigger AWS projects. Since it isn’t focused around a single aspect of AWS, it’s a lot easier to build various resources in CDK. For example, take a look at the below code. While it’s still pretty long, it’s much easier to read and understand what’s happening in each step. If you had multiple distributions to create, you could even wrap all this in a helper function to make things easier, something you can’t do in Serverless config.
In CDK, each AWS service you can work with is usually set up as its own library, so if you want to use it, you just import that library and call it. CDK also has extra libraries available that can make it much easier for you to set up commonly used but fairly complex patterns, such as the load-balanced Fargate application pattern. You can use other standard libraries for your chosen language’s platform as well.
Like with Serverless, if you’re using JavaScript or TypeScript, there’s a library available for CDK to bundle your Lambda functions with Webpack, called aws-cdk-webpack-lambda-function.
CDK’s Not Perfect Either
One of CDK’s weaknesses, however, is that it’s a little more complicated to set up a Lambda function with it. Unlike the Serverless config shown previously, below is what it looks like to set up a Lambda in CDK. Like the Serverless example, we’re setting up an EventBridge rule to run the Lambda automatically at set intervals, and granting the Lambda function access to an S3 bucket. It’s a lot more code than the config you’d need in Serverless. Of course, you can always write your own helper functions to simplify this.
It’s worth remembering that CDK still uses CloudFormation as its backing, so you’ll still run up against the 200 resources per stack limit. Unlike Serverless though, with CDK it’s really easy to set up multiple stacks and share resources between them. You can see an example below.
This is a great way to avoid hitting the limit. You can also use a setup like this to put all of the resources you don’t want to lose if you need to take down a stack, such as an RDS database, into a “base” stack, then move the other resources that just handle functionality, like Lambda or Fargate, into other stacks. That way you can destroy the other stacks if you need to reset something while keeping your persistent data intact.
Another issue you might run into, at least if using JavaScript, is that generic JS objects can cause problems with CDK. For example, take a look at the below code. If you’re using something like this to handle constants that change between environments, you’ll sometimes run into problems when CDK tries to convert your code into CloudFormation.
This has to do with the way CDK treats JS objects. It sometimes wants to convert them into CloudFormation because all of the resources you create in your code are actually just JS objects themselves. There’s a pretty simple workaround though, just wrap it in a function like so, and call the function instead of the variable directly.
So Which One Do I Want To Use?
If you’re absolutely certain you’re going to be sticking to AWS Lambda and few other AWS resources, then Serverless can be a good choice for its simplicity, especially if you know you only need a few Lambda functions (few enough to stay below the CloudFormation resource limit). Serverless may also be a good choice if you’re looking for something that’s compatible with other cloud platforms.
If you want to do anything more complex, like setting up a Fargate instance behind a load balancer, you’re better off going with CDK. CDK’s broader first-class support for various AWS services makes it a much better choice for complex projects. Moreover, if you’re building out something large that’s likely to hit the CloudFormation resource limit, CDK’s easy way of sharing resources across stacks makes it easier to work around the limit and organize your AWS resources in a useful way. Being developed by the AWS team also means you’re likely to see functionality come to CDK that may never be available through Serverless.
Lastly, it’s worth mentioning that while both Serverless and CDK have plugins to support using Webpack if you’re using JavaScript or TypeScript, the plugin for Serverless can conflict with other plugins if you’re using them because of the way Serverless packaging works.