Serverless Framework vs CDK vs SST: my pick for 2026
DEV Community

Serverless Framework vs CDK vs SST: my pick for 2026

In short

All three tools get a Lambda API into AWS within minutes, but they differ in engine, licence and target audience.

I use the Serverless Framework for Lambda-heavy backends, CDK for platforms with a lot of infrastructure and SST for full-stack apps in TypeScript teams.

The biggest pitfall is switching tools halfway through a project, because the state of your infrastructure does not simply move with you.

What you will learn in this article

  • Deploy the same Lambda API with Serverless Framework, CDK and SST
  • How engine, state and local development differ between the three tools
  • What the Serverless Framework v4 licence means for companies
  • Which questions help you choose a tool

Serverless Framework vs CDK: I get asked this almost every week, and for a few years now SST has been the third candidate in the room.

I started out with the Serverless Framework, wrote CDK for many years and keep coming back to SST to try it out. That is why I know the honest answer is not “tool X is the best”. It depends on what you build, who will still maintain it in three years and how much infrastructure grows around your Lambda functions.

In this article I build the same small API three times: once with the Serverless Framework, once with AWS CDK and once with SST. After that I compare the three tools where it really matters in day-to-day work.

At the end you get my clear recommendation on which tool I pick in 2026, and why the Serverless Framework vs CDK question is often settled before the first line of code.

Three tools, one goal

All three tools describe infrastructure as code (IaC): you write down in a file which Lambda functions, APIs and tables should exist, and the tool makes sure AWS looks exactly like that.

The differences lie in how you describe it and what happens under the hood.

Serverless Framework: YAML focused on functions

The Serverless Framework is the oldest of the three. You describe your service in a serverless.yml, with functions and the events that trigger them at the centre. From that, the framework generates a CloudFormation template and deploys it.

Since version 4 it builds TypeScript handlers itself with its built-in esbuild, so you no longer need a build plugin. Version 3 is open source, but according to the vendor it has not been maintained since 31 December 2024.

AWS CDK: a real programming language, CloudFormation underneath

The AWS Cloud Development Kit (CDK) is the official tool from AWS. You write infrastructure in TypeScript, Python, Java, C#/.NET or Go. Reusable building blocks are called constructs: a NodejsFunction construct, for example, bundles your TypeScript code and creates the Lambda function including its IAM role.

CDK also produces a CloudFormation template in the end. The project is licensed under Apache 2.0, and the CLI is now released from its own repository with its own version number.

SST: TypeScript configuration with the Pulumi engine

SST describes the whole app in a single sst.config.ts. The key difference: SST does not use CloudFormation. According to its docs it uses Pulumi as the deployment engine and talks to the AWS APIs directly.

SST keeps its state in an S3 bucket in your account. SST is open source under the MIT licence and has been at version 4 since February 2026.

The main change from v3 is the jump of the Pulumi AWS provider from v6 to v7. If you only use SST components, your code stays as it is, but the state has to be migrated once with sst refresh.

Serverless Framework vs CDK vs SST in practice

For the comparison I build a fictional mini API for a bike rental: GET /bikes returns all available bikes, optionally filtered by station. Behind it sits a single Lambda function in TypeScript behind an API Gateway HTTP API.

Small enough to show everything, big enough to make the differences visible.

Prerequisites

  • An AWS account and local credentials (for example via aws configure sso), ideally in a test account.
  • Node.js 22 or newer and npm.
  • For Serverless Framework v4, a free account with the vendor, because the CLI requires you to sign in.
  • For CDK, run cdk bootstrap once per account and region.

Step 1: The shared Lambda handler

The handler is identical in all three variants. It lives in src/bikes.ts and uses the types from @types/aws-lambda:

// src/bikes.ts
import type { APIGatewayProxyHandlerV2 } from "aws-lambda";
type Bike = { id: string; model: string; station: string; available: boolean; };
// Demo data - in a real app this would come from DynamoDB
const bikes: Bike[] = [
  { id: "b-101", model: "City Classic", station: "hauptbahnhof", available: true },
  { id: "b-102", model: "Trekking Pro", station: "hauptbahnhof", available: false },
  { id: "b-103", model: "E-Bike Flow", station: "altstadt", available: true },
  { id: "b-104", model: "Lastenrad Max", station: "altstadt", available: true },
];
export const handler: APIGatewayProxyHandlerV2 = async (event) => {
  const station = event.queryStringParameters?.station;
  const result = bikes.filter((bike) => bike.available && (!station || bike.station === station),
  );
  return {
    statusCode: 200,
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ count: result.length, bikes: result }),
  };
};

So that TypeScript knows the types, install the dev dependencies once:

npm init -y
npm install --save-dev typescript @types/aws-lambda @types/node

Step 2: Deploy with the Serverless Framework

The complete infrastructure fits into this serverless.yml. You point the handler straight at the TypeScript file, and the built-in esbuild bundles it during deployment:

# serverless.yml
service: fahrradverleih-api
frameworkVersion: "4"
provider:
  name: aws
  runtime: nodejs22.x
  architecture: arm64
  region: eu-central-1
  memorySize: 256
  timeout: 5
functions:
  listBikes:
    handler: src/bikes.handler
    events:
      - httpApi:
          path: /bikes
          method: get

Then install the CLI, sign in once and deploy:

npm install -g serverless
serverless login
serverless deploy --stage dev

At the end, the framework prints the API URL under endpoint. A curl "<endpoint>/bikes?station=altstadt" then returns {"count":2,"bikes":[...]}.

Clean up with serverless remove --stage dev.

Step 3: Deploy with AWS CDK

With CDK you write the infrastructure as a TypeScript class. First the dependencies:

npm install aws-cdk-lib constructs
npm install --save-dev aws-cdk esbuild tsx

The stack creates the function, the HTTP API and the route. NodejsFunction bundles the handler with esbuild, which is why esbuild is in the dev dependencies above:

// lib/bike-api-stack.ts
import { CfnOutput, Duration, Stack, type StackProps } from "aws-cdk-lib";
import { HttpApi, HttpMethod } from "aws-cdk-lib/aws-apigatewayv2";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import type { Construct } from "constructs";
export class BikeApiStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const listBikes = new NodejsFunction(this, "ListBikes", {
      entry: "src/bikes.ts",
      handler: "handler",
      runtime: Runtime.NODEJS_22_X,
      architecture: Architecture.ARM_64,
      memorySize: 256,
      timeout: Duration.seconds(5),
    });
    const api = new HttpApi(this, "BikeApi");
    api.addRoutes({
      path: "/bikes",
      methods: [HttpMethod.GET],
      integration: new HttpLambdaIntegration("ListBikesIntegration", listBikes),
    });
    new CfnOutput(this, "ApiUrl", { value: api.apiEndpoint });
  }
}

Add the entry point of the app and a small cdk.json that tells CDK how to start the app:

// bin/app.ts
import { App } from "aws-cdk-lib";
import { BikeApiStack } from "../lib/bike-api-stack";
const app = new App();
new BikeApiStack(app, "FahrradverleihApi", {
  env: { region: "eu-central-1" },
});
{ "app": "npx tsx bin/app.ts" }

Now bootstrap once per account and region, then deploy:

npx cdk bootstrap
npx cdk deploy

In the output you will find the value FahrradverleihApi.ApiUrl under Outputs. Append /bikes and you get the same response as with the Serverless Framework.

Remove everything with npx cdk destroy.

If you want to learn CDK from scratch, my article “Deploy a Lambda function with CDK and TypeScript” walks through every step in detail.

Step 4: Deploy with SST

You set up SST with one command in the project folder. It creates an sst.config.ts and installs the sst package:

npx sst@latest init

Then replace the contents of the configuration with this variant. The line with /// <reference …> loads the types that SST generates under .sst/ on first run:

// sst.config.ts
/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: "fahrradverleih",
      home: "aws",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: input?.stage === "production",
      providers: { aws: { region: "eu-central-1" } },
    };
  },
  async run() {
    const api = new sst.aws.ApiGatewayV2("BikeApi");
    api.route("GET /bikes", {
      handler: "src/bikes.handler",
      architecture: "arm64",
      memory: "256 MB",
    });
    return { url: api.url };
  },
});

removal and protect are set on purpose here: in the production stage, resources are kept on removal and sst remove refuses to run. In every other stage, SST cleans up completely.

Deploying and removing works like this:

npx sst deploy --stage dev
npx sst remove --stage dev

At the end, SST prints the URL that you return from run(). SST stores the state and a passphrase in an S3 bucket named sst-state-… and in SSM Parameter Store, both in your account.

🎬 From code to AWS: three paths - this animated diagram only runs on my site: watch it on sascha-ms.de

The differences that matter day to day

All three variants deliver the same API. Still, they feel very different once the project grows.

I have summarised the key points of Serverless Framework vs CDK vs SST in a table:

  • Serverless Framework v4 / AWS CDK v2 / SST v4
  • Configuration: YAML (or a JS/TS file) / TypeScript, Python, Java, C#, Go / TypeScript
  • Engine: CloudFormation / CloudFormation / Pulumi (Terraform providers via bridge)
  • State: in the CloudFormation stack / in the CloudFormation stack / S3 bucket plus SSM parameter in your own account
  • Licence: free up to USD 2 million annual revenue, subscription above that; sign-in required / Apache 2.0 / MIT
  • Local development: serverless dev routes real invocations to your machine / cdk watch with hotswap / sst dev with live functions
  • Strength: Lambda-centric services, little code / any AWS infrastructure, your own constructs / full-stack apps with a frontend

Engine and state: CloudFormation or Pulumi

On the engine, Serverless Framework vs CDK is almost a draw: both end up in CloudFormation. Deployments can take a bit of patience, but there is a big upside: AWS manages the state, rollbacks happen automatically, and any team with AWS experience can read a stack in the console.

You can also mix both worlds without trouble, because ordinary stacks come out at the end.

SST takes a different route with Pulumi. You skip the detour through CloudFormation stacks, and besides AWS you can use providers such as Cloudflare. In return, the state is your responsibility, even though SST keeps it in your account.

You notice this at the latest with a major version jump: moving to v4 meant migrating every stage once with sst refresh, and SST explicitly calls this migration one-way.

Local development: how fast is the feedback?

All three have caught up here. serverless dev attaches the functions of an already deployed stage to your machine, so real invocations in AWS run against your local code. The mode refuses production stages named prod and production.

sst dev works in a similar way and also starts a watcher for infrastructure changes and your frontend. With CDK I use cdk watch, which pushes code changes straight into the Lambda function via hotswap without redeploying the whole stack.

Keep hotswap to development stacks, though, because it deliberately bypasses CloudFormation.

Licence and cost: the Serverless Framework is no longer free

This point is often underestimated. Since v4, the Serverless Framework CLI requires you to sign in. It stays free for individuals and organisations with at most USD 2 million in annual revenue; larger companies need a subscription.

Billing works in credits per “service instance”, meaning per service, stage and region that exists for more than ten days in a month. In CI pipelines you use an access key or, with a subscription, the licence key in the SERVERLESS_LICENSE_KEY variable.

I walk through moving an existing v3 project in Migrate to Serverless Framework v4.

For a start-up this hardly matters. In a large enterprise with many services and stages, however, it becomes a real budget item and often a procurement question too.

CDK and SST cost nothing as tools; you only pay for the AWS resources.

Learning curve and team fit

Almost everyone can read YAML. That is why a serverless.yml is the most approachable option for beginners and for people from operations or the business side.

CDK requires your team to understand a programming language and the construct model. In return you get loops, type checking, tests and your own libraries.

SST sits in between: TypeScript, but with a small set of very well chosen components. If you already build with Next.js or Astro, you will feel at home right away.

Serverless Framework vs CDK and SST: how I decide today

My thesis: the tool matters less than the question of who maintains the code in three years. Switching halfway through a project is expensive, because you cannot simply move resources holding data from one stack to the next. So it pays to make this decision deliberately.

This is the decision guide I use myself:

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.