Stacks, Change Sets & Drift
A CloudFormation stack is the unit you actually deploy: it groups every resource described by one template (a VPC, an EC2 instance, a security group, a database, and so on) into a single thing you can create, update, and delete together. Once your infrastructure lives in a stack, you stop clicking around the Console and start treating your servers like code. This page covers the day-to-day operations that keep stacks safe in production: previewing updates with change sets, finding sneaky manual edits with drift detection, and scaling across accounts and regions with nested stacks and StackSets.
What a stack is
When you submit a template to CloudFormation, AWS creates a stack and provisions every resource in it. If anything fails, CloudFormation rolls the whole thing back to the last known-good state, so you never end up with a half-built environment. The stack tracks the status of every resource and remembers the exact template that produced it.
Each stack has a name (like prod-web-app), a status (CREATE_COMPLETE, UPDATE_ROLLBACK_COMPLETE, etc.), and a list of resources with their logical IDs (the name you wrote in the template, e.g. MyWebServer) mapped to physical IDs (the real AWS identifier, e.g. i-0a1b2c3d4e5f).
When to use a stack: any time you want a group of resources to share a lifecycle — created together, updated together, deleted together. When NOT to: don’t cram unrelated resources (your shared VPC and a throwaway test instance) into one stack, because deleting the stack deletes everything in it.
aws cloudformation describe-stacks --stack-name prod-web-app
Output:
{
"Stacks": [
{
"StackName": "prod-web-app",
"StackStatus": "CREATE_COMPLETE",
"CreationTime": "2026-06-10T14:22:01.000Z",
"Outputs": [
{ "OutputKey": "WebServerId", "OutputValue": "i-0a1b2c3d4e5f" }
]
}
]
}
Change sets — preview before you apply
A change set is a “what would happen if I applied this update?” report. Instead of pushing a new template straight into a live stack, you create a change set and CloudFormation tells you exactly which resources will be added, modified, or replaced — without touching anything yet. You then choose to execute it or throw it away.
The word that should make you nervous is Replacement. Some template edits modify a resource in place (cheap, no downtime); others force CloudFormation to delete the old resource and create a new one. Renaming an RDS database’s DBInstanceIdentifier, for example, replaces the database — and the new one starts empty. A change set surfaces this before you cause an outage.
Gotcha: Always run a change set before updating production. An innocent-looking one-line template edit can trigger a full resource replacement (new instance, new IP, lost data). The change set’s
Replacement: Truecolumn is your early warning.
Console steps
- Open the CloudFormation console and select your stack (e.g.
prod-web-app). - Click Stack actions → Create change set for current stack.
- Choose Replace current template and upload your edited template (or edit in the designer).
- Click Next through the parameters, then Create change set and give it a name.
- Wait for the status to reach
CREATE_COMPLETE, then open the Changes tab and inspect the Replacement column for every row. - If it looks safe, click Execute change set. If not, click Delete change set — nothing was applied.
CLI equivalent
aws cloudformation create-change-set \
--stack-name prod-web-app \
--change-set-name add-https-listener \
--template-body file://template.yaml \
--capabilities CAPABILITY_NAMED_IAM
aws cloudformation describe-change-set \
--stack-name prod-web-app \
--change-set-name add-https-listener
Output:
{
"Changes": [
{
"ResourceChange": {
"Action": "Modify",
"LogicalResourceId": "WebServerSecurityGroup",
"PhysicalResourceId": "sg-0a1b2c3d",
"ResourceType": "AWS::EC2::SecurityGroup",
"Replacement": "False"
}
}
],
"Status": "CREATE_COMPLETE"
}
When you’re happy:
aws cloudformation execute-change-set \
--stack-name prod-web-app \
--change-set-name add-https-listener
Change sets are free; you only pay for whatever resources the update actually provisions.
Drift detection — find out-of-band changes
Drift is the difference between what your template says and what actually exists in AWS. It happens when someone edits a resource directly in the Console or with a one-off CLI command instead of changing the template — for example, manually adding an inbound rule to sg-0a1b2c3d. CloudFormation no longer matches reality, and your next stack update may silently undo the manual change or behave unexpectedly.
Drift detection compares each resource’s live configuration against the template and reports which resources are IN_SYNC, MODIFIED, or DELETED.
Console steps
- In the CloudFormation console, select the stack.
- Click Stack actions → Detect drift.
- Wait for detection to finish, then click Stack actions → View drift results.
- Each drifted resource shows the expected vs actual properties side by side.
CLI equivalent
aws cloudformation detect-stack-drift --stack-name prod-web-app
# returns a StackDriftDetectionId; poll it:
aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id 11111111-2222-3333-4444-555566667777
Output:
{
"StackDriftStatus": "DRIFTED",
"DriftedStackResourceCount": 1,
"DetectionStatus": "DETECTION_COMPLETE"
}
Discipline that prevents pain: Manage stack resources only through the template, and run drift detection on a schedule (e.g. a weekly EventBridge rule). Drift accumulates quietly; the longer it goes undetected, the riskier your next deployment becomes. To fix drift, re-apply the template via a change set rather than hand-patching the Console.
Nested stacks and StackSets — for scale
As templates grow, a single file becomes unwieldy. Two features help you scale.
| Feature | What it does | When to use |
|---|---|---|
| Nested stack | A stack created as a resource inside a parent stack (AWS::CloudFormation::Stack). Lets you reuse common templates (a standard VPC, a standard logging setup). | One account/region, but you want modular, reusable building blocks. |
| StackSet | Deploys the same template across many accounts and regions from one place, using AWS Organizations. | Org-wide guardrails — e.g. a security baseline in every account. |
A nested stack referenced from a parent looks like this:
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/network.yaml
Parameters:
VpcCidr: "10.0.0.0/16"
Create a StackSet from the CLI:
aws cloudformation create-stack-set \
--stack-set-name org-security-baseline \
--template-body file://baseline.yaml \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
When NOT to use StackSets: for a single app in a single account, they add needless complexity — a plain stack is enough.
Best Practices
- Run a change set before every production update and read the Replacement column carefully.
- Never edit stack-managed resources by hand in the Console; change the template instead.
- Schedule drift detection (weekly via EventBridge) and reconcile drift through a change set.
- Use
DeletionPolicy: Retainand termination protection on stacks that own stateful resources like databases. - Keep templates modular with nested stacks; use StackSets only when you genuinely span accounts or regions.
- Store templates in version control and review them like application code.