AWS CloudFormation is the native infrastructure as code service of Amazon Web Services that creates, updates and deletes cloud resources from declarative templates written in JSON or YAML. Instead of clicking through a console, an engineer describes the desired resources and their properties, and CloudFormation works out the order of operations and the API calls needed to reach that state.
Within the Cloud discipline, CloudFormation occupies a specific niche: it is a managed provisioning engine tied to a single provider. The service itself stores the deployment state, so there is no separate state file to protect, and it can roll back automatically when a deployment fails halfway.
How CloudFormation turns templates into stacks
CloudFormation deploys a template as a stack, a single unit of management that owns every resource the template declares. When a stack is created, the service parses the template, builds a dependency graph from references between resources, and provisions independent resources in parallel while respecting the order that references imply.
Each resource has a logical ID in the template and a physical ID assigned by the provider, such as an actual bucket name or instance identifier. CloudFormation keeps the mapping between them, which is how it knows what to modify on the next update. A resource that is changed outside CloudFormation therefore causes configuration drift, which the service can detect but does not repair by itself.
A template is organized into named top-level sections. Only Resources is mandatory; the others make a template reusable across environments and accounts.
| Section | Purpose | Typical content |
|---|---|---|
| Parameters | Inputs supplied at deployment | Environment name, instance size, CIDR range |
| Mappings | Static lookup tables | AMI IDs per region |
| Conditions | Boolean logic for optional resources | Create a replica only in production |
| Resources | The resources to manage (required) | AWS::S3::Bucket, AWS::EC2::VPC |
| Outputs | Values exposed after deployment | Endpoint URLs, exported IDs |
| Transform | Macros applied before processing | AWS::Serverless-2016-10-31 for SAM |
Intrinsic functions such as Ref, Fn::GetAtt, Fn::Sub and Fn::ImportValue connect resources and stacks. Cross-stack references through exports and imports let a network stack publish a VPC ID that application stacks consume, while CloudFormation blocks deletion of an export that is still imported.
Change sets, rollback and stack policies
A change set is a preview of what an update will do before it runs. It lists every resource that will be added, modified or removed and, crucially, whether a modification requires replacement. Replacement means the old physical resource is deleted and a new one is created, which for a database or a named bucket can mean data loss or downtime.
The effect of a property change depends on the resource type, and the documentation of each property states which behavior applies.
| Update behavior | What happens | Risk level |
|---|---|---|
| No interruption | Resource updated in place | Low |
| Some interruption | Resource restarted or briefly unavailable | Medium |
| Replacement | New resource created, old one deleted | High for stateful resources |
When a create or update fails, CloudFormation by default performs an automatic rollback to the last known good state. Engineers can also attach CloudWatch alarms as rollback triggers, so a deployment that raises an error rate during a monitoring window of up to 180 minutes is reverted. A stack policy protects critical resources from accidental update, and DeletionPolicy: Retain or Snapshot preserves data when a resource leaves the stack.
Scaling CloudFormation across accounts and regions
Large organizations rarely run one stack. CloudFormation offers several mechanisms for composition and fleet deployment, and choosing among them shapes how teams share infrastructure.
- Nested stacks embed a child template as an
AWS::CloudFormation::Stackresource, which helps keep templates under the 1 MB template size limit and the 500-resource limit per stack. - StackSets deploy the same template to many accounts and regions at once, often through AWS Organizations for guardrails such as logging roles.
- Modules package reusable resource groups that appear as a single resource type in templates.
- Hooks run proactive checks before provisioning, which is a form of policy as code inside the service.
- Registry extensions add third-party or private resource types through the CloudFormation resource provider model.
The AWS CDK and AWS SAM sit on top of CloudFormation. CDK lets developers write infrastructure in TypeScript, Python or other languages and synthesizes a CloudFormation template; SAM is a transform that shortens serverless definitions. In both cases, CloudFormation remains the deployment engine that actually applies the changes.
CloudFormation compared with other infrastructure as code tools
CloudFormation is best understood against its neighbors: the multi-cloud tools Terraform and OpenTofu, the general-purpose language approach of Pulumi, and the Azure counterpart Bicep. The main differences lie in state handling, provider scope and authoring language.
| Tool | State storage | Provider scope | Authoring style |
|---|---|---|---|
| CloudFormation | Managed by AWS | AWS only (plus registry types) | JSON or YAML templates |
| Terraform / OpenTofu | State file in a backend | Multi-cloud and SaaS | HCL |
| Pulumi | Managed service or backend | Multi-cloud | General-purpose languages |
| Bicep | Managed by Azure | Azure only | Bicep DSL compiled to ARM |
The practical trade-off is operational simplicity versus reach. CloudFormation needs no state backend, no locking setup and no provider version pinning, and new AWS features often gain support quickly. Terraform covers more platforms in one workflow but requires the team to manage Terraform state carefully. Configuration management tools such as Ansible, Chef and Puppet address a different layer: they configure software inside servers rather than provisioning the cloud resources themselves.
Common pitfalls and practical guidance
Most CloudFormation incidents come from a small set of recurring mistakes. Teams that run it at scale learn to recognize the symptoms early.
| Symptom | Likely cause | Remedy |
|---|---|---|
| Stack stuck in UPDATE_ROLLBACK_FAILED | Rollback cannot restore a resource changed manually | Continue rollback and skip the affected resource |
| Database recreated after an update | Property change forced replacement | Always review change sets; set DeletionPolicy |
| Export cannot be changed | Value still imported by another stack | Use parameters or SSM parameters for loose coupling |
| Template grows unmanageable | One monolithic stack | Split by lifecycle into nested or separate stacks |
| Deployed state differs from template | Manual console edits | Run drift detection and restrict console write access |
A sound working pattern is to separate stacks by lifecycle: long-lived network and data layers in one set of stacks, frequently deployed application layers in another. Templates should be validated with cfn-lint and checked with policy tools such as cfn-guard before deployment, and production changes should always pass through a reviewed change set in a CI/CD pipeline rather than direct console updates.
Put simply
CloudFormation is like handing a detailed building plan to a contractor instead of giving instructions one brick at a time. You write down what you want, such as a network, a few servers and a database, and the service builds all of it in the right order.
If something goes wrong halfway, it tears down the unfinished work and returns to the last working version. When you change the plan later, it shows you exactly what will be altered before it touches anything. The key idea is that the written plan becomes the single source of truth for what exists in the account.
In practice
A mid-sized retail company runs its online shop on AWS in three environments: development, staging and production. The platform team keeps one network template that creates a VPC with public and private subnets across three Availability Zones, and a second template for the application tier with a load balancer, an Auto Scaling group and an Aurora database. A parameter selects the instance size, so development uses small instances while production uses larger ones.
Every change goes through a pipeline that runs cfn-lint, creates a change set and waits for approval. During one release, the change set showed that renaming the database cluster identifier would trigger replacement of the production database. The reviewer stopped the deployment, and the team kept the old identifier. The result is identical, repeatable environments and no unplanned outages caused by infrastructure changes.