What is CloudFormation?
AWS CloudFormation is Amazon’s native Infrastructure as Code (IaC) service — a way to describe the cloud resources you want in a text file and let AWS build them for you. You write a template (a JSON or YAML file listing servers, networks, databases, and how they connect), hand it to CloudFormation, and it provisions everything in the right order, tracks what it created, and cleans up after itself if something goes wrong. This matters because it turns “click 20 buttons and hope you remember” into a repeatable, reviewable file you commit to Git.
What CloudFormation actually does
You give CloudFormation a template. It reads the resources you declared and creates a stack — a single named collection of all those resources managed together as one unit. From then on, the stack is the thing you operate on: you update it, you delete it, you inspect it.
Three jobs CloudFormation handles for you automatically:
- Dependency ordering. If a server needs a security group (a virtual firewall) before it can launch, CloudFormation figures that out from the references in your template and creates them in the correct sequence. You do not write the order yourself.
- State tracking. CloudFormation remembers exactly what it created and the settings of each resource. Unlike Terraform, there is no separate state file for you to store and protect — AWS keeps the state for you inside the stack.
- Rollback on failure. If creating the stack fails partway through, CloudFormation rolls back and deletes everything it made, so you are not left with half-built, half-billed infrastructure.
Because the state lives inside the stack on AWS, you never have to manage, lock, or back up a state file the way Terraform users do. This is one of CloudFormation’s biggest day-one wins for AWS-only teams.
When to use CloudFormation (and when not to)
When to use it: you are committed to AWS, you have more than one environment (say, staging and production), and you want IaC without paying for or learning an extra tool. CloudFormation itself is free — you only pay for the resources it creates. It has the deepest, fastest support for new AWS services because Amazon builds it.
When NOT to use it: you need to manage resources across multiple clouds (use Terraform), or you want to define infrastructure using a real programming language with loops and conditionals (use the AWS CDK, which compiles down to CloudFormation anyway). Raw YAML templates can also get verbose for very large systems.
| Tool | Language | Best for | Extra cost |
|---|---|---|---|
| CloudFormation | YAML / JSON | AWS-only teams wanting native IaC | None |
| AWS CDK | TypeScript, Python, etc. | Developers who prefer real code | None |
| Terraform | HCL | Multi-cloud, large ecosystems | Free (paid Cloud option) |
A minimal template
A template has a Resources section listing what to create. Here is one that makes an S3 bucket (object storage) and a security group, written in YAML:
AWSTemplateFormatVersion: "2010-09-09"
Description: A tiny stack with a bucket and a security group
Resources:
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: devcraftly-app-assets-2026
WebSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTPS from anywhere
VpcId: vpc-0a1b2c3d
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
The AWSTemplateFormatVersion is just a fixed format date — always "2010-09-09" — and must stay quoted so the build does not read it as a number.
Creating a stack
You can deploy a template from either the AWS Management Console (the web dashboard) or the AWS Command Line Interface (CLI — the terminal tool, v2 in 2026).
Console steps:
- Open the CloudFormation service in the Console.
- Click Create stack then With new resources (standard).
- Under Specify template, choose Upload a template file and select your YAML file.
- Click Next, give the stack a name like
app-stack, and click Next again. - Review the resources, then click Submit.
CLI equivalent:
aws cloudformation create-stack \
--stack-name app-stack \
--template-body file://template.yaml \
--capabilities CAPABILITY_NAMED_IAM
Output:
{
"StackId": "arn:aws:cloudformation:us-east-1:111122223333:stack/app-stack/0a1b2c3d-1234-5678-90ab-0a1b2c3d4e5f"
}
The --capabilities flag is required only when a template creates IAM (Identity and Access Management — AWS permissions) resources, which acknowledges you reviewed those permissions.
To watch progress, ask for the stack’s events:
aws cloudformation describe-stack-events --stack-name app-stack \
--query "StackEvents[].{Resource:LogicalResourceId,Status:ResourceStatus}"
Output:
[
{ "Resource": "WebSG", "Status": "CREATE_COMPLETE" },
{ "Resource": "AppBucket", "Status": "CREATE_COMPLETE" },
{ "Resource": "app-stack", "Status": "CREATE_COMPLETE" }
]
Updating and deleting
To change infrastructure, edit the template and update the stack — CloudFormation works out the difference and changes only what is needed.
aws cloudformation update-stack \
--stack-name app-stack \
--template-body file://template.yaml
A change set lets you preview those changes before applying them — create one with aws cloudformation create-change-set and inspect it before executing. To tear everything down, delete the stack and CloudFormation removes every resource it created:
aws cloudformation delete-stack --stack-name app-stack
The drift gotcha
This is the trap that catches everyone. Once a resource is owned by a stack, treat it as off-limits to manual editing. If you open the Console and change a stack-managed security group rule by hand, reality no longer matches the template. This mismatch is called drift.
Drift is dangerous for two reasons. First, your next update-stack may silently revert your manual fix back to whatever the template says, undoing your change. Second, an update can outright fail if CloudFormation expected a resource in a state it no longer finds. You can detect this with drift detection (aws cloudformation detect-stack-drift --stack-name app-stack), but the real cure is discipline: change the template, never the live resource.
Warning: failed stack creates roll back and delete everything by default. That is usually what you want, but it also means a typo near the end of a long template can throw away 15 minutes of provisioning. For production stacks, consider
--disable-rollbackwhile debugging so you can inspect what failed.
Best practices
- Treat stack-managed resources as owned by the template — never edit them by hand in the Console, to avoid drift.
- Keep templates in version control (Git) and review changes like any other code.
- Use change sets to preview updates before applying them, especially in production.
- Split large systems into multiple smaller stacks (network, app, data) so a failure has a smaller blast radius.
- Add a
DeletionPolicy: Retainto stateful resources like databases and S3 buckets so deleting a stack does not wipe your data. - Always quote version strings and numeric-looking values in YAML to keep templates valid.
- Run drift detection periodically to catch out-of-band changes before they break a deploy.