What to use for a serverless backend
Cloudformation, Serverless Framework, AWS CDK, SST, Terraform?
API resources visualized in AWS CloudFormation Designer
CloudFormation
Using CloudFormation is like using binary instead of a programming language.
All the other frameworks generate CloudFormation files (JSON/YML) for AWS to use to generate resources.
Here is an example CloudFormation generated from SST:
Serverless Framework
As well as generating Cloudformation files, the Serverless Framework comes with tools for development and deployment
With this framework you create serverless.yml files, these serve as stacks. Here you'll import function files, mapping templates, and even other resources generated by separate serverless.yml files, like Cognito and Dynamodb.
Here is an API in a serverless.yml converted to json for viewing:
Pros:
- CLI ease of use - deploy functions and resources independently or deploy/remove the whole stack.
- Easy deployment - with SEED you can update your backend with git.
- Documentation is great, lots of good examples.
Cons:
- Can be wordy.
- Importing other resources, using
fn gett att
not very intuitive. - YML files error with improper spacing
CDK
AWS's own serverless framework - it's a multi-language cloud development kit. While for AWS, it can be used with other providers with Terraform (CDKTF). cdk watch!!!
Pros:
-
TypeScript support, no need to use YML files. This allows IDE intellisense / autocomplete.
Dynamic variables in YML files can be confusing, when using a language like TypeScript, you can use the variable in-line.
Have a lot of similar IAM roles? No need to write them all out (YML), iterate over them (JS).
Cons:
- Documentation sucks
- New - still doesn't have all functionality, improving fast though. (couldn't use SES couldn't be used in cognito before)
-
Some errors I found initially difficult to resolve:
Property does not exist on type 'StackProps'
Type "AWS_IAM" is not assignable to type 'ApiAuthorizationType | undefined'
'table' does not exist in type 'StackProps'
Property 'table' does not exist on type 'StackProps'
Argument of type
{ table: any; }
is not assignable to parameter of type 'StackProps'.Property 'table' does not exist on type 'DynamoDbStack'
-
SST
Why use SST over CDK?
Example SST file:
Typescript file in JSON for in browser viewing
-
Example ApiStack
import * as sst from "@serverless-stack/resources"; import { CorsHttpMethod } from "@aws-cdk/aws-apigatewayv2" export default class ApiStack extends sst.Stack { api constructor(scope: sst.App, id: string, props: any) { super(scope, id, props); const { usersTable, receiversTable, privateUsers, sessionData } = props; // const domain = (scope.stage === "prod") ? "api.talktree.me" : "dev-api.talktree.me" this.api = new sst.Api(this, "Api", { cors: true, defaultAuthorizationType: sst.ApiAuthorizationType.AWS_IAM, defaultFunctionProps: { environment: { UsersTable: usersTable.tableName, ReceiversTable: receiversTable.tableName, PrivateUser: privateUsers.tableName, SessionData: sessionData.tableName, }, }, routes: { "GET /getUsers": "src/getUsers.handler", "POST /createUnpaidSession": "src/createUnpaidSession.handler", "POST /getUser": "src/getUser.handler", "POST /saveNotionId": "src/saveNotionId.handler" }, }); this.api.attachPermissions([usersTable, receiversTable, privateUsers, sessionData, "ses"]); // Show the endpoint in the output this.addOutputs({ "ApiEndpoint": this.api.url, "Routes": JSON.stringify(this.api.routes), }); } }
Pros:
- Constructs like SST.api greatly simplifies CDK
- CDK CLI support with
npx sst cdk
; very useful resolving deployment issues.
Cons:
- These names are complicated af - can I simplify them just the tiniest bit.. (dynamodb tables)
- AWS only
- Uses 3 environments which doesn't work seamlessly with Next.js.
Terraform
Terraform by HashiCorp is like a platform-agnostic version of SST. You aren't locked into AWS, but it uses its own language. Can still use CDK (CDKTF).