Introduction
I’m currently building a React app.
In the past, I hosted it on S3 + CloudFront, so I thought I’d do the same this time. I went ahead and created the resources using the AWS Management Console, but then I caught myself thinking:
- What settings did I use last time?
- Did I misconfigure something this time?
- Clicking through the console is such a hassle…
That’s when I decided to look into how to provision AWS resources with IaC (Infrastructure as Code).
In this post, I’ll walk through the main IaC tools available on AWS, compare their strengths, and share recommendations for different development scenarios—frontend and backend.
Why IaC?
Using IaC comes with some clear benefits:
Reproducible setups
→ Easily spin up multiple environments (e.g., dev, staging, prod).Fewer human errors
→ No risk of misclicking in the console.Automation-friendly
→ Since your infra is code, you can seamlessly integrate it into pipelines (e.g., GitHub Actions).
IaC Options on AWS
The three main IaC options in the AWS ecosystem are:
- CloudFormation
- AWS SAM (Serverless Application Model)
- AWS CDK (Cloud Development Kit)
Here’s a quick overview:
CloudFormation
- AWS’s core IaC service
- Define resources in JSON or YAML
- Pros: Covers all AWS services, lots of official templates available
- Cons: Can get verbose; hard to manage at scale
→ Best for: “I want simple templates” or “I want to learn from AWS’s official examples.”
AWS SAM
- Built on top of CloudFormation
- Tailored for serverless apps (Lambda, API Gateway, DynamoDB, etc.)
- Handy CLI (
sam build
,sam local invoke
,sam deploy
) - Pros: Minimal config for serverless workloads
- Cons: Not great for non-serverless services
→ Best for: “I want to quickly build & deploy a serverless app.”
AWS CDK
- Lets you define infra using programming languages (TypeScript, Python, Java, etc.)
- Compiles down to CloudFormation under the hood
- Pros: Use loops, conditionals, and abstractions—perfect for complex infra
- Cons: Slightly steeper learning curve
→ Best for: “I want to use my favorite language” or “I need to manage large/complex setups.”
Practical Examples
Frontend Example: React on S3 + CloudFront
- Recommended: CDK or CloudFormation
- Typical setup: Deploy React static files to S3, distribute via CloudFront
CDK Example (TypeScript):
import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
export class FrontendStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, "FrontendBucket", {
websiteIndexDocument: "index.html",
publicReadAccess: false,
});
new cloudfront.CloudFrontWebDistribution(this, "FrontendCDN", {
originConfigs: [
{
s3OriginSource: { s3BucketSource: bucket },
behaviors: [{ isDefaultBehavior: true }],
},
],
});
}
}
Serverless Backend Example: Lambda + API Gateway
- Recommended: AWS SAM
- You can write it in CloudFormation, but SAM makes it much easier
SAM Example (YAML):
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.lambda_handler
Runtime: python3.11
Events:
ApiEvent:
Type: Api
Properties:
Path: /hello
Method: get
Non-Serverless Backend Example: ECS + VPC + RDS
- Recommended: CDK
- Great for managing complex infra like ECS + VPC + RDS
CDK Example (ECS Fargate):
import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ec2 from "aws-cdk-lib/aws-ec2";
const vpc = new ec2.Vpc(this, "MyVpc");
const cluster = new ecs.Cluster(this, "MyCluster", { vpc });
new ecs.FargateService(this, "MyService", {
cluster,
taskDefinition: new ecs.FargateTaskDefinition(this, "TaskDef"),
});
Summary
CloudFormation
→ The fundamental tool for defining AWS infra in YAML/JSON.AWS SAM
→ Optimized for serverless apps, especially Lambda-heavy projects.AWS CDK
→ Flexible, expressive, and powerful for complex or large-scale infra.
Even if you’re used to clicking around in the AWS Console, adopting IaC unlocks big advantages: reproducibility, environment consistency, and automation.
If you’re new to IaC, I recommend starting small—maybe with your frontend setup—then gradually tying it into CI/CD (like GitHub Actions) for full automation.
Top comments (0)