Serverless Frameworks Compared
Serverless Frameworks Compared
Serverless computing promised to free developers from infrastructure management. The irony is that choosing how to deploy serverless functions has become its own infrastructure decision, with a half-dozen frameworks competing to be your deployment layer.
This guide compares the frameworks that matter in 2026: SST (Ion), Serverless Framework v4, AWS SAM, Pulumi, and Terraform. Each takes a fundamentally different approach to the same problem -- getting your code running on Lambda (or equivalent) with the right triggers, permissions, and infrastructure around it.
The Quick Version
If you want the recommendation up front:
- Building a full-stack app with AWS? SST Ion.
- Just deploying Lambda functions, nothing fancy? AWS SAM.
- Multi-cloud or complex infrastructure beyond serverless? Pulumi or Terraform.
- Migrating from Serverless Framework v3? Evaluate whether to move to SST or SAM rather than upgrading to v4.
Now let's dig into why.
SST (Ion)
SST -- originally the Serverless Stack Toolkit -- reinvented itself in 2024 with Ion, a complete rewrite that replaced its CloudFormation-based architecture with Pulumi/Terraform under the hood. It's the most opinionated framework on this list, and for full-stack applications on AWS, it's the best developer experience available.
How It Works
SST Ion uses a TypeScript-first configuration model. You define your infrastructure in sst.config.ts:
// sst.config.ts
export default $config({
app(input) {
return {
name: "my-app",
removal: input.stage === "production" ? "retain" : "remove",
home: "aws",
};
},
async run() {
const bucket = new sst.aws.Bucket("Uploads");
const api = new sst.aws.Function("Api", {
handler: "packages/functions/src/api.handler",
link: [bucket],
url: true,
});
const site = new sst.aws.Nextjs("Site", {
link: [api, bucket],
});
return {
api: api.url,
site: site.url,
};
},
});
The Killer Feature: Resource Linking
SST's link system is genuinely innovative. When you link a resource to a function, SST automatically:
- Grants the IAM permissions needed
- Injects the resource's connection details as environment variables
- Provides a type-safe SDK to access linked resources
// In your function code
import { Resource } from "sst";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
await s3.send(new PutObjectCommand({
Bucket: Resource.Uploads.name, // Type-safe reference
Key: "file.txt",
Body: "hello",
}));
No more manually wiring IAM policies. No more hardcoded bucket names or ARNs. The framework handles the plumbing.
Local Development: sst dev
sst dev starts a local development environment that proxies Lambda invocations from AWS to your local machine. Your functions run locally with hot reload, but they interact with real AWS resources (DynamoDB, S3, SQS, etc.).
sst dev
This is dramatically better than the emulator-based approach (SAM local, LocalStack) because you're testing against real AWS services. The trade-off is that you need AWS credentials and an internet connection for local dev.
Pros
- Best-in-class DX for full-stack AWS applications
- Type-safe infrastructure configuration
- Resource linking eliminates IAM policy boilerplate
- Excellent local development with live Lambda debugging
- Built-in support for Next.js, Remix, Astro, and other frameworks
- Multiplayer stages -- each developer gets their own isolated stack
Cons
- AWS-only (no multi-cloud)
- Opinionated -- if you disagree with SST's opinions, you'll fight the framework
- Ion is relatively new (2024) -- some rough edges remain
- Smaller community than Terraform or Serverless Framework
- Uses Pulumi under the hood, which adds a dependency layer
Cost
SST the framework is free and open source. SST Console (their dashboard) has a free tier and paid plans starting at $20/month per workspace.
Serverless Framework v4
The Serverless Framework was the original tool that popularized serverless development starting in 2015. It uses YAML configuration and a plugin ecosystem to deploy Lambda functions with triggers.
The v4 Licensing Controversy
Serverless Framework v4 (released 2024) introduced a significant licensing change: it requires a paid license for organizations with over $2M in annual revenue. This drove a substantial portion of the community to migrate to other tools.
If you're under the revenue threshold, it's still free. But the licensing change signals a direction that makes many teams uncomfortable.
Configuration
# serverless.yml
service: my-service
frameworkVersion: "4"
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
environment:
UPLOADS_BUCKET: !Ref UploadsBucket
functions:
api:
handler: src/api.handler
events:
- httpApi:
method: GET
path: /items
processUpload:
handler: src/process.handler
events:
- s3:
bucket: !Ref UploadsBucket
event: s3:ObjectCreated:*
resources:
Resources:
UploadsBucket:
Type: AWS::S3::Bucket
Plugin Ecosystem
The Serverless Framework's plugin ecosystem is its biggest advantage. Need offline development? serverless-offline. Need webpack bundling? serverless-webpack. Need per-function IAM roles? serverless-iam-roles-per-function. There's a plugin for almost everything.
plugins:
- serverless-offline
- serverless-esbuild
- serverless-iam-roles-per-function
Pros
- Mature ecosystem with hundreds of plugins
- Large community -- lots of Stack Overflow answers and blog posts
- Multi-cloud support (AWS, Azure, GCP) though AWS is the primary focus
- Simple YAML configuration for straightforward Lambda deployments
- Dashboard with monitoring, CI/CD, and observability
Cons
- v4 licensing is a dealbreaker for many organizations
- YAML configuration gets painful at scale -- deeply nested, error-prone, hard to refactor
- CloudFormation under the hood means slow deployments and cryptic error messages
- Local development (
serverless-offline) is a mediocre emulator - No type safety in configuration
When to Use It
Honestly? If you're starting a new project in 2026, there are better options. If you have an existing Serverless Framework v3 project, evaluate migration costs to SST or SAM rather than upgrading to v4. The licensing change and the YAML-first approach make it less compelling than the alternatives.
AWS SAM (Serverless Application Model)
SAM is AWS's official serverless framework. It extends CloudFormation with serverless-specific resource types and provides a CLI for local development, testing, and deployment.
Configuration
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs20.x
Timeout: 30
MemorySize: 256
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/api.handler
Events:
GetItems:
Type: HttpApi
Properties:
Method: GET
Path: /items
Policies:
- S3ReadPolicy:
BucketName: !Ref UploadsBucket
UploadsBucket:
Type: AWS::S3::Bucket
Local Development
SAM provides Docker-based local emulation:
# Invoke a function locally
sam local invoke ApiFunction --event events/get-items.json
# Start a local API Gateway
sam local start-api
# Start a local Lambda endpoint
sam local start-lambda
The local emulation is decent for basic testing but doesn't replicate all AWS service behaviors. DynamoDB queries, S3 operations, and SQS interactions need a real AWS environment or LocalStack for accurate testing.
SAM Accelerate
sam sync (SAM Accelerate) speeds up the development cycle by bypassing CloudFormation for code-only changes:
sam sync --watch --stack-name my-app-dev
This watches for file changes and deploys code updates in seconds instead of minutes. Infrastructure changes still go through CloudFormation, but code changes are pushed directly to Lambda.
Pros
- First-party AWS tool -- guaranteed compatibility and long-term support
- Free, open source, no licensing concerns
- Direct CloudFormation integration -- anything CloudFormation supports, SAM supports
- SAM Accelerate makes iterative development fast
- Policy templates simplify IAM (e.g.,
S3ReadPolicy,DynamoDBCrudPolicy) - Strong integration with AWS tooling (CodePipeline, CodeBuild, X-Ray)
Cons
- YAML/CloudFormation syntax is verbose and unforgiving
- Local emulation is limited compared to SST's live dev approach
- AWS-only (by design)
- No plugin ecosystem -- you get what SAM provides
- CloudFormation deployment speed is slow for infrastructure changes (minutes, not seconds)
- Error messages from CloudFormation are often unhelpful
When to Use It
SAM is the right choice when: you want the safety of an official AWS tool, your serverless project is primarily Lambda + API Gateway + DynamoDB, and you don't need the DX features of SST. It's also the right choice for organizations with strict vendor requirements that mandate first-party tools.
Pulumi
Pulumi is an infrastructure-as-code tool that lets you define infrastructure using general-purpose programming languages (TypeScript, Python, Go, C#, Java). It's not serverless-specific, but it's excellent at serverless deployments.
Configuration
// index.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
const bucket = new aws.s3.Bucket("uploads");
const api = new awsx.apigateway.API("api", {
routes: [
{
path: "/items",
method: "GET",
eventHandler: new aws.lambda.Function("getItems", {
runtime: "nodejs20.x",
handler: "index.handler",
code: new pulumi.asset.AssetArchive({
".": new pulumi.asset.FileArchive("./src/get-items"),
}),
environment: {
variables: {
BUCKET_NAME: bucket.bucket,
},
},
}),
},
],
});
const role = new aws.iam.RolePolicyAttachment("lambdaS3", {
role: api.routes[0].eventHandler.role.name,
policyArn: aws.iam.ManagedPolicy.AmazonS3ReadOnlyAccess,
});
export const apiUrl = api.url;
export const bucketName = bucket.bucket;
Why Pulumi for Serverless
The advantage of Pulumi over YAML-based tools becomes clear at scale:
- Loops and conditionals. Deploy 10 Lambda functions with a
forloop, not 10 copy-pasted YAML blocks. - Abstraction. Write reusable components as functions or classes.
- Type safety. TypeScript catches misconfigurations at compile time.
- Testing. Unit test your infrastructure with standard testing frameworks.
// Reusable component
function createApiHandler(name: string, path: string, handlerDir: string) {
return new aws.lambda.Function(name, {
runtime: "nodejs20.x",
handler: "index.handler",
code: new pulumi.asset.AssetArchive({
".": new pulumi.asset.FileArchive(handlerDir),
}),
});
}
Pros
- Real programming languages -- loops, conditionals, abstractions, testing
- Multi-cloud support (AWS, Azure, GCP, Kubernetes)
- Type-safe infrastructure configuration
- Can import existing CloudFormation/Terraform resources
- State management (Pulumi Cloud or self-managed backends)
- Component model for reusable infrastructure patterns
Cons
- Not serverless-specific -- you're writing lower-level infrastructure code
- More verbose than SST for common serverless patterns
- Learning curve for the Pulumi resource model
- Pulumi Cloud (state management) is a paid service for teams (self-hosted backend is free)
- No built-in local development for serverless functions
When to Use It
Pulumi is the right choice when: you need multi-cloud, your infrastructure extends well beyond serverless, you want to use real programming languages for IaC, or you're already using it for other infrastructure.
Terraform
Terraform uses HCL (HashiCorp Configuration Language) and is the most widely adopted infrastructure-as-code tool. Like Pulumi, it's not serverless-specific, but plenty of teams use it for serverless deployments.
Configuration
# main.tf
resource "aws_lambda_function" "api" {
function_name = "api-handler"
runtime = "nodejs20.x"
handler = "index.handler"
filename = data.archive_file.api.output_path
role = aws_iam_role.lambda.arn
environment {
variables = {
BUCKET_NAME = aws_s3_bucket.uploads.bucket
}
}
}
resource "aws_s3_bucket" "uploads" {
bucket_prefix = "uploads-"
}
resource "aws_apigatewayv2_api" "api" {
name = "api"
protocol_type = "HTTP"
}
resource "aws_apigatewayv2_integration" "api" {
api_id = aws_apigatewayv2_api.api.id
integration_type = "AWS_PROXY"
integration_uri = aws_lambda_function.api.invoke_arn
payload_format_version = "2.0"
}
resource "aws_apigatewayv2_route" "get_items" {
api_id = aws_apigatewayv2_api.api.id
route_key = "GET /items"
target = "integrations/${aws_apigatewayv2_integration.api.id}"
}
# Plus IAM role, policy attachments, API stage, Lambda permission...
The Verbosity Problem
Look at that Terraform config. It's explicit and declarative, which is good for infrastructure teams managing hundreds of resources. But for a simple "Lambda function behind API Gateway," it's a lot of boilerplate. You need to manually wire up:
- IAM role and policy attachments
- API Gateway integration
- API Gateway route
- Lambda permission for API Gateway to invoke the function
- API Gateway stage and deployment
SST and SAM handle all of this with a few lines. Terraform makes you spell it out.
Terraform Modules
The community addresses this with modules:
module "lambda_function" {
source = "terraform-aws-modules/lambda/aws"
version = "~> 7.0"
function_name = "api-handler"
handler = "index.handler"
runtime = "nodejs20.x"
source_path = "./src/api"
attach_policy_json = true
policy_json = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject"]
Resource = "${aws_s3_bucket.uploads.arn}/*"
}]
})
}
OpenTofu
Worth mentioning: OpenTofu is the open-source fork of Terraform, created after HashiCorp changed Terraform's license to BSL in 2023. It's API-compatible with Terraform and backed by the Linux Foundation. If licensing matters to you, OpenTofu is the drop-in replacement.
Pros
- Largest IaC ecosystem -- providers for every cloud and service
- HCL is purpose-built for infrastructure (not a general-purpose language)
- Massive community, documentation, and module library
terraform plangives you a clear preview of changes before applying- State management is well-understood and battle-tested
- Multi-cloud support
Cons
- Very verbose for serverless patterns
- HCL is limited -- no real loops (for_each is awkward), no functions, no abstractions
- No local development support for serverless
- No concept of "environments" or "stages" without wrapper tooling (Terragrunt)
- State locking and management adds operational overhead
When to Use It
Terraform is the right choice when: your organization already uses it for other infrastructure, you need multi-cloud, your platform team manages infrastructure centrally, or you want the largest ecosystem of providers and modules.
Deployment Speed Comparison
How long does it take to deploy a change to a single Lambda function?
| Framework | Code-only Change | Infrastructure Change |
|---|---|---|
| SST (sst deploy) | 5-15 seconds | 30-90 seconds |
| SST (sst dev -- live) | Instant (local) | N/A |
| Serverless Framework | 30-60 seconds | 60-180 seconds |
| AWS SAM (sam sync) | 5-10 seconds | 60-180 seconds |
| AWS SAM (sam deploy) | 60-120 seconds | 60-180 seconds |
| Pulumi | 10-30 seconds | 30-120 seconds |
| Terraform | 15-45 seconds | 30-120 seconds |
CloudFormation-based tools (Serverless Framework, SAM without sync) are the slowest because every deployment creates a CloudFormation changeset.
Vendor Lock-in: An Honest Assessment
Every serverless framework involves some degree of lock-in. Here's where the lock-in actually lives:
AWS Lambda itself is the biggest lock-in. Your function code uses AWS SDK calls, IAM permissions, API Gateway request/response formats, and AWS-specific event sources. The framework you choose to deploy it is a minor concern compared to the runtime lock-in.
SST locks you into AWS and SST's abstraction layer. If SST disappears, you'd need to recreate infrastructure in another tool.
Serverless Framework is the most portable in theory (multi-cloud), but in practice, most serverless.yml files are deeply AWS-specific.
SAM locks you into AWS and CloudFormation. Since it's a CloudFormation extension, your templates are portable to any CloudFormation tool.
Pulumi and Terraform are the most portable frameworks -- they support multiple clouds, and your infrastructure code is decoupled from any specific serverless model.
The honest truth: if you're building on AWS Lambda, you're locked into AWS regardless of framework. Optimize for developer experience, not theoretical portability.
The Bottom Line
For full-stack applications on AWS: SST Ion. The developer experience -- live Lambda debugging, resource linking, type-safe config -- is a generation ahead of everything else.
For simple Lambda deployments on AWS: AWS SAM. It's free, first-party, and SAM Accelerate makes the development cycle fast. The YAML is annoying but manageable for small projects.
For multi-cloud or infrastructure-heavy projects: Pulumi if you want to use TypeScript/Python, Terraform if your team already knows HCL.
For new projects: Don't start with Serverless Framework v4. The licensing situation and the availability of better alternatives make it hard to justify.
The serverless framework you choose matters less than your application architecture. Pick one that fits your team's existing skills, deploy with it consistently, and focus your energy on the code running inside the functions. That's where the actual value is.