CloudFormation change sets, drift, import and cross-stack references

Read a change set (Action, Replacement True/Conditional/False, property-level before and after), detect drift and what it can't see, revert drift with drift-aware change sets (REVERT_DRIFT), import existing resources (DeletionPolicy required, no other changes), how DeletionPolicy behaves on delete versus replacement, and exports versus Fn::GetStackOutput for cross-stack, cross-account and cross-Region references.

markdownreferencev4M64Q-6G5Mstage: buildtrust: officialservice: cloudformationinterface: cliinterface: sdkinterface: iacchange setdescribe-change-setinclude-property-valuesReplacement ConditionalRequiresRecreationEvaluation Dynamicdrift detectionDRIFTEDMODIFIEDNOT_CHECKEDdrift limitationsdrift-aware change setREVERT_DRIFTSyncWithActualresource importIMPORT change setDeletionPolicyRetainSnapshotRetainExceptOnCreatereplacement deletes old resourceExportFn::ImportValuelist-importsFn::GetStackOutputcross-account stack outputcross-region reference

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

Change sets, drift, import and cross-stack references

Before executing a change set, read its Replacement column. True means CloudFormation creates a new resource and deletes the old one, whatever its DeletionPolicy says. For a database or a bucket, that is data loss.

Reading a change set

aws cloudformation describe-change-set --stack-name s --change-set-name c --include-property-values

FieldValues and meaning
ActionAdd, Modify (may interrupt or replace), Remove, Import, Dynamic (nested stacks only: the action can't be known in advance), SyncWithActual (drift-aware change sets: drift status reset, resource unchanged)
Replacement (Modify only)True: always replaced. Conditional: replacement depends on a value only known at deploy time (RequiresRecreation: Always with Evaluation: Dynamic). False: updated in place. When several changes apply, the one with the most impact wins (Always > Conditional > Never)
ScopeWhat changes: Properties, Tags, …
Details[].TargetPath (e.g. /Properties/Description), BeforeValue, AfterValue, AttributeChangeType (Add, Modify, Remove) with --include-property-values

A change set is a preview, not a promise. It runs pre-deployment checks (syntax, name conflicts, quotas), but runtime failures such as custom resource logic still happen at execution. Executing one change set deletes the stack's other change sets.

DeletionPolicy

ValueOn stack delete, or when the resource is removed from the template
Delete (default)Deleted
RetainKept, no longer managed, and still billed
SnapshotSnapshot, then delete. Supported on EBS volumes, RDS instances and clusters, DocumentDB, Neptune, ElastiCache clusters and replication groups, and Redshift
RetainExceptOnCreateKept, except when the operation that created it rolls back
  • Defaults that differ: AWS::RDS::DBCluster, and an AWS::RDS::DBInstance without DBClusterIdentifier, default to Snapshot.
  • None of these apply on replacement. The old physical resource is always deleted then.
  • Retained resources with fixed names cause the next deploy to fail with already exists. Import them or rename (reference/cloudformation/errors.md).

Drift detection

aws cloudformation detect-stack-drift --stack-name s starts it, describe-stack-drift-detection-status --stack-drift-detection-id <id> reports progress, and describe-stack-resource-drifts --stack-name s lists the drifted resources. (The command names come from the SDK operations; the user-guide page shows only the console.)

  • Stack: DRIFTED, IN_SYNC or NOT_CHECKED. Resource: MODIFIED, DELETED, IN_SYNC or NOT_CHECKED. Property: ADD, REMOVE or NOT_EQUAL.
  • Stack-level tags are checked. Nested stacks are not: run detection on each one.

What drift detection can't see:

  • Properties you didn't set in the template, even if they changed. Set a property explicitly, even to its default, if you want it watched.
  • KMSKeyId on any resource, Lambda function code, and write-only values such as an IAM login profile password.
  • Unsupported resource types, which show NOT_CHECKED.

False alarms:

  • Equal values in other units (1024 MB vs 1GB): align the template with the actual value.
  • Default array items the service adds.
  • Attachment resources, such as AWS::EC2::SecurityGroupIngress, whose target is in another stack.

Fixing drift

OptionHow
Drift-aware change set (revert)create-change-set … --deployment-mode REVERT_DRIFT (SDK DeploymentMode: "REVERT_DRIFT"), or console Drift aware change set. Three-way comparison: actual state, previous deployment, new template. Drifted resources are set back to the template. Where you change the template to match reality, only the drift status resets (SyncWithActual)
Accept the changeEdit the template to the actual value and deploy
Remove and re-importRetain, remove from the template, import again (below)

Drift-aware limits:

  • Immutable properties aren't reconciled. Write-only properties compare against the previous deployment's values.
  • Tag keys absent from the template aren't touched.
  • AWS-managed values the template doesn't set, such as an Auto Scaling group's desired capacity, are left alone.
  • Attachments from other stacks (for example AWS::IAM::Policy attached to this stack's role) count as drift and may be reverted.
  • 27 resource types fall back to a two-way comparison, among them AWS::RDS::DBProxy, AWS::MSK::Cluster and AWS::IAM::OIDCProvider.

CDK --hotswap deployments create drift on purpose. The CLI then prompts for cdk deploy --revert-drift (reference/cdk/bootstrap-roles-and-trust.md).

Importing existing resources

  1. Add each resource to the template with its identifier (for example BucketName), its required properties, and a DeletionPolicy (any value). The template must describe the whole stack. aws cloudformation get-template-summary --template-url … lists the identifier properties.
  2. Create a change set of type IMPORT with the resources to import, then execute it. Statuses are IMPORT_IN_PROGRESS → IMPORT_COMPLETE, or IMPORT_ROLLBACK_*.
  3. Run drift detection afterwards. CloudFormation doesn't check that your template matches the real configuration.

Restrictions:

  • An import can't create, delete or modify anything else.
  • A resource can't be in two stacks in one Region. IAM roles, Route 53 zones and CloudFront distributions are global, so check other Regions too.
  • Nesting is limited to one level.
  • Restrict which types can be imported with cloudformation:ImportResourceTypes.

Other paths include auto-import (cdk deploy --import-existing-resources adopts unmanaged resources whose custom names match), the IaC generator, and stack refactoring to move resources between stacks.

Cross-stack references

Export + Fn::ImportValueFn::GetStackOutput
ScopeSame account and RegionAlso cross-Region (Region) and cross-account (RoleArn); not cross-partition
IntegrityStrong. While imported, the exporter can't be deleted and the value can't change. aws cloudformation list-imports --export-name <n> shows who holds itWeak. Resolved at create or update; the consumer isn't told when the producer changes and must be re-deployed
NamesExport names unique per account and RegionStackName + OutputName; no export needed
VpcId:
  Fn::GetStackOutput:
    StackName: network
    OutputName: VpcId
    Region: us-west-2                                    # optional
    RoleArn: arn:aws:iam::<producer-account>:role/ReadOutputs   # optional, cross-account
  • The cross-account role lives in the producer account. It allows cloudformation:DescribeStacks on that stack and trusts the consumer stack's execution role, which is used when RoleArn is omitted.
  • Use it as a property value or inside Fn::Join, Fn::If or Fn::Select. Elsewhere it returns InternalFailure (reference/cloudformation/errors.md).
  • Don't use the !GetStackOutput short form with other short forms inside it.

Read this document as markdown — the same bytes an agent receives.