Deploying to AWS in 2026 looks different than it did five years ago. The ecosystem has matured, new tools have emerged, and the "right" approach depends more than ever on your team's size, experience, and what you're building.
This guide covers the main options for deploying backend applications to AWS, from clicking around in the console to fully automated infrastructure-as-code. We'll look at the trade-offs, show code examples, and help you pick the right approach.
The AWS Console is where most developers start. You log in, click through wizards, and configure services manually.
When it works:
When it doesn't:
The console is fine for learning, but you'll quickly hit limits. There's no version control, no way to review changes, and no easy path to reproduce what you built. Most teams graduate to something else within months.
Encore takes a different approach than traditional infrastructure-as-code. Instead of writing separate infrastructure definitions, you declare what your application needs directly in your backend code. Encore Cloud then provisions AWS resources automatically.
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";
import { Topic } from "encore.dev/pubsub";
// This creates an RDS PostgreSQL database
const db = new SQLDatabase("users", {
migrations: "./migrations",
});
// This creates SNS/SQS
const signups = new Topic<SignupEvent>("signups", {
deliveryGuarantee: "at-least-once",
});
// This creates a Fargate service or Lambda
export const createUser = api(
{ method: "POST", path: "/users", expose: true },
async (req: CreateUserRequest) => {
const user = await db.exec`INSERT INTO users ...`;
await signups.publish({ userId: user.id });
return user;
}
);
When you push code, Encore analyzes it and provisions the corresponding AWS resources: RDS for databases, SNS/SQS for Pub/Sub, Fargate or Lambda for compute, S3 for object storage, CloudWatch for cron jobs.
What you get:
Trade-offs:
Encore works well for teams that want AWS infrastructure ownership without becoming infrastructure experts. Companies like Groupon use this approach to power their backends at scale. The open-source framework has 11k+ GitHub stars.
CloudFormation is AWS's native infrastructure-as-code service. You define resources in YAML or JSON templates, and CloudFormation creates and manages them.
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyDatabase:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: db.t3.micro
Engine: postgres
MasterUsername: admin
MasterUserPassword: !Ref DBPassword
AllocatedStorage: 20
MyLambda:
Type: AWS::Lambda::Function
Properties:
Runtime: nodejs18.x
Handler: index.handler
Code:
S3Bucket: my-deployment-bucket
S3Key: lambda.zip
What you get:
Trade-offs:
CloudFormation is reliable but painful to write. Most teams either use a wrapper (like CDK) or switch to Terraform.
The Cloud Development Kit (CDK) lets you write CloudFormation in real programming languages. You write TypeScript, Python, or Go, and CDK synthesizes CloudFormation templates.
import * as cdk from 'aws-cdk-lib';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class MyStack extends cdk.Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);
const database = new rds.DatabaseInstance(this, 'Database', {
engine: rds.DatabaseInstanceEngine.postgres({
version: rds.PostgresEngineVersion.VER_15,
}),
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3,
ec2.InstanceSize.MICRO
),
});
const fn = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
environment: {
DATABASE_URL: database.instanceEndpoint.hostname,
},
});
}
}
What you get:
Trade-offs:
CDK is a significant improvement over raw CloudFormation, but you still need to understand AWS services deeply.
Terraform is the industry standard for infrastructure-as-code. It uses HashiCorp Configuration Language (HCL) and works across AWS, GCP, Azure, and hundreds of other providers.
// Terraform HCL syntax
provider "aws" {
region = "us-east-1"
}
resource "aws_db_instance" "main" {
identifier = "my-database"
engine = "postgres"
engine_version = "15"
instance_class = "db.t3.micro"
allocated_storage = 20
username = "admin"
password = var.db_password
}
resource "aws_lambda_function" "api" {
function_name = "my-api"
runtime = "nodejs18.x"
handler = "index.handler"
filename = "lambda.zip"
environment {
variables = {
DATABASE_URL = aws_db_instance.main.endpoint
}
}
}
What you get:
Trade-offs:
The trade-off is that you're maintaining two codebases: your application and your infrastructure. This adds overhead but gives you more control over individual resource settings.
Pulumi is like Terraform but uses real programming languages instead of HCL. You write TypeScript, Python, Go, or C# to define infrastructure.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const database = new aws.rds.Instance("database", {
engine: "postgres",
engineVersion: "15",
instanceClass: "db.t3.micro",
allocatedStorage: 20,
username: "admin",
password: config.requireSecret("dbPassword"),
});
const fn = new aws.lambda.Function("api", {
runtime: "nodejs18.x",
handler: "index.handler",
code: new pulumi.asset.FileArchive("./lambda"),
environment: {
variables: {
DATABASE_URL: database.endpoint,
},
},
});
What you get:
Trade-offs:
Pulumi offers an alternative to Terraform's HCL syntax if you prefer using TypeScript or Python for infrastructure definitions.
SST focuses on serverless AWS deployments. It's built on CDK but optimized for Lambda, API Gateway, and related services.
import { Api, Table } from "sst/constructs";
export function API({ stack }: StackContext) {
const table = new Table(stack, "users", {
fields: { id: "string", email: "string" },
primaryIndex: { partitionKey: "id" },
});
const api = new Api(stack, "api", {
routes: {
"POST /users": "packages/functions/src/create.handler",
},
});
api.bind([table]);
return { api };
}
What you get:
Trade-offs:
SST targets serverless applications on AWS. It's built on CDK, so you'll still need to understand AWS concepts.
| Approach | Learning Curve | Flexibility | Maintenance | Best For |
|---|---|---|---|---|
| Console | Low | High | None (not repeatable) | Learning, experiments |
| Encore | Low | Medium | Low | Teams wanting AWS without DevOps |
| CloudFormation | High | High | High | AWS-native shops |
| CDK | Medium | High | Medium | Teams comfortable with AWS |
| Terraform | Medium | Very High | Medium | Multi-cloud, large infra |
| Pulumi | Medium | Very High | Medium | Developers who prefer real code |
| SST | Low-Medium | Medium | Low | Serverless applications |
Choose the Console if:
Choose Encore if:
Choose CloudFormation/CDK if:
Choose Terraform if:
Choose Pulumi if:
Choose SST if:
Most teams should start with the simplest option that meets their needs, then evolve if necessary. If you're building a backend application and don't want to become an infrastructure expert, Encore is worth trying. If you need maximum flexibility or multi-cloud support, Terraform is the industry standard.
Whatever you choose, avoid the console for anything you need to reproduce. Infrastructure-as-code isn't optional in 2026—it's how professional teams ship software.