CloudFormation stack operations — what each call changes

What CreateStack, UpdateStack, CreateChangeSet/ExecuteChangeSet, DeleteStack, ContinueUpdateRollback and RollbackStack change and need — capabilities, the stack service role (RoleARN) and iam:PassRole, OnFailure and DisableRollback, timeouts, express mode (DeploymentConfig), DeletionMode and RetainResources, the stack statuses each leaves behind, IAM condition keys, and which quotas are adjustable — with a TypeScript change-set deploy.

markdownreferencev47Q2F-SG1Rstage: buildtrust: officialservice: cloudformationinterface: cliinterface: sdkCreateStackUpdateStackCreateChangeSetExecuteChangeSetDeleteStackContinueUpdateRollbackRollbackStackCapabilitiesCAPABILITY_IAMCAPABILITY_NAMED_IAMCAPABILITY_AUTO_EXPANDRoleARN service roleiam:PassRole CloudFormationOnFailureDisableRollbackTimeoutInMinutesRetainExceptOnCreateDeploymentConfigexpress modeDeletionModeRetainResourcestermination protectionstack status codescloudformation:RoleArnCloudFormation quotaswaitUntilChangeSetCreateComplete

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

CloudFormation stack operations

Prefer change sets (create, review, execute) over a direct UpdateStack for anything shared. You see each resource's Add, Modify or Remove, and whether it will be replaced, before anything changes. Pass a service role (RoleARN) so that deployments don't depend on whoever runs them.

The calls

CallWhat it changesNotes
CreateStackCreates the stack and every resourceOnFailure = ROLLBACK (default), DELETE or DO_NOTHING; or DisableRollback: true (not both). TimeoutInMinutes (minimum 1): after it, CREATE_FAILED, then rollback if enabled. RetainExceptOnCreate: true deletes resources created by this operation on rollback, even those with Retain
UpdateStackApplies the new template or parameters directlyWithout changes you get No updates are to be performed. (reference/cloudformation/errors.md). --disable-rollback keeps successful changes on failure (UPDATE_FAILED)
CreateChangeSetNothing yet. It computes the diff (ChangeSetType CREATE for a new stack)Pre-deployment checks run here, as warnings only. A change set with nothing to do ends FAILED with The submitted information didn't contain changes.
ExecuteChangeSetApplies that change setDeletes every other change set for the stack. --disable-rollback is allowed
DeleteStackDeletes resources by their DeletionPolicy (Retain and Snapshot leave billable things behind)RetainResources (for a stack in DELETE_FAILED), DeletionMode: FORCE_DELETE_STACK (for stacks stuck in DELETE_FAILED). Termination protection refuses it
ContinueUpdateRollbackResumes a rollback from UPDATE_ROLLBACK_FAILEDResourcesToSkip, --force-rollback (guides/cloudformation/fix-failed-stack.md)
RollbackStackReturns a *_FAILED stack (rollback disabled) to its last stable stateDeletes the stack if it never had one

What it costs

CloudFormation calls don't carry a price of their own in the fetched sources (UNVERIFIED; check the pricing page for hooks and third-party resource types). The cost is the resources the template creates or replaces. Several things leave cost behind:

  • a replacement runs the old and new resource side by side until cleanup;
  • Retain and Snapshot leave billable resources after a delete;
  • a failed create with rollback disabled leaves its successful resources running.

Review Replacement and Add rows in a change set before executing.

Capabilities

You acknowledge capabilities explicitly, or the call fails with InsufficientCapabilitiesException:

  • CAPABILITY_IAM: the template has IAM resources (Role, Policy, ManagedPolicy, User, Group, AccessKey, InstanceProfile, UserToGroupAddition).
  • CAPABILITY_NAMED_IAM: those resources have custom names. It also covers unnamed ones.
  • CAPABILITY_AUTO_EXPAND: macros (AWS::Serverless, AWS::Include) used while creating a stack directly rather than by change set. Stacks that combine macros and nested stacks must be created directly with it.

The service role (RoleARN)

  • CloudFormation assumes this role for the operation and always uses it for every later operation on the stack. That holds even when the person updating can't pass the role, as long as they're allowed to operate on the stack. Give it least privilege.
  • Without one, CloudFormation reuses the role already associated with the stack, or else a session from the caller's credentials. Then every deployer needs permissions for every service in the template.
  • The role trusts cloudformation.amazonaws.com, and whoever first attaches it needs iam:PassRole on it (guides/iam/create-service-role.md).
  • A service role also lets slow resources (RDS, Auto Scaling, nested stacks) run past the default wait.
  • To restrict which roles can be used, condition on cloudformation:RoleArn in IAM policies. Other condition keys are cloudformation:ResourceTypes, ImportResourceTypes, TemplateUrl, StackPolicyUrl, ChangeSetName and TargetRegion.

The CDK sets this up for you: its cfn-exec-role is the service role (reference/cdk/bootstrap-roles-and-trust.md).

Express mode (since 2026-06-30)

--deployment-config '{"mode": "EXPRESS"}' on create-stack, update-stack, delete-stack and create-change-set. In the SDK it is DeploymentConfig: { Mode: "EXPRESS" }. The CDK uses cdk deploy --express.

  • The operation reports complete when each resource's create, update or delete call succeeds, not when the resource is ready. EC2 user data may still be running and CloudFront may still be deploying. Dependency order is unchanged.
  • Rollback is off by default (user guide and announcement). The SDK field DisableRollback documents a default of false, so set it explicitly.
  • Outputs that reference a resource attribute still wait for that resource. Custom resources still wait for their response (cap the wait with ServiceTimeout). Nested stacks inherit the mode. StackSets aren't supported.
  • After an express delete, names may still be in use for a while, so a quick re-create can collide.
  • Don't use it where the deployment must prove the resources work, such as production gates.

Statuses an operation leaves

StatusMeaningAllowed next
CREATE_COMPLETE, UPDATE_COMPLETE, UPDATE_ROLLBACK_COMPLETEStableAnything
ROLLBACK_COMPLETEA create failed and was cleaned upDelete only
CREATE_FAILED / UPDATE_FAILED with rollback disabledSuccessful resources keptRetry, update (keep --disable-rollback), RollbackStack, change sets
UPDATE_ROLLBACK_FAILEDThe rollback itself failedContinueUpdateRollback or delete; no change sets
DELETE_FAILEDSome resources weren't deletedDelete again (retain or force); no updates
REVIEW_IN_PROGRESSA stack ID exists but no template or resources yet (the state a not-yet-executed CREATE change set leaves, by the hub's reading)Counts against the stack quota
IMPORT_*An import is running or rolling backSee reference/cloudformation/change-sets-drift-and-import.md

DetailedStatus: CONFIGURATION_COMPLETE on an event means the resource is configured and CloudFormation is waiting for it to stabilize.

Deploy by change set (TypeScript)

import { readFile } from "node:fs/promises";
import {
  CloudFormationClient, CreateChangeSetCommand, DescribeChangeSetCommand,
  ExecuteChangeSetCommand, DeleteChangeSetCommand, waitUntilChangeSetCreateComplete,
  waitUntilStackUpdateComplete, waitUntilStackCreateComplete,
} from "@aws-sdk/client-cloudformation";

const cfn = new CloudFormationClient({});

export async function deploy(stackName: string, templatePath: string, roleArn: string, isNew: boolean) {
  const ChangeSetName = `deploy-${Date.now()}`;
  await cfn.send(new CreateChangeSetCommand({
    StackName: stackName,
    ChangeSetName,
    ChangeSetType: isNew ? "CREATE" : "UPDATE",
    TemplateBody: await readFile(templatePath, "utf8"),
    Capabilities: ["CAPABILITY_NAMED_IAM"],
    RoleARN: roleArn,
  }));
  try {
    await waitUntilChangeSetCreateComplete({ client: cfn, maxWaitTime: 600 }, { StackName: stackName, ChangeSetName });
  } catch {
    const cs = await cfn.send(new DescribeChangeSetCommand({ StackName: stackName, ChangeSetName }));
    if (cs.StatusReason?.includes("didn't contain changes")) {
      await cfn.send(new DeleteChangeSetCommand({ StackName: stackName, ChangeSetName }));
      return "no changes";
    }
    throw new Error(`Change set failed: ${cs.StatusReason}`);
  }
  const cs = await cfn.send(new DescribeChangeSetCommand({ StackName: stackName, ChangeSetName }));
  for (const c of cs.Changes ?? []) {
    const r = c.ResourceChange;
    console.log(r?.Action, r?.LogicalResourceId, r?.ResourceType, "replacement:", r?.Replacement);
  }
  await cfn.send(new ExecuteChangeSetCommand({ StackName: stackName, ChangeSetName }));
  const wait = isNew ? waitUntilStackCreateComplete : waitUntilStackUpdateComplete;
  await wait({ client: cfn, maxWaitTime: 3600 }, { StackName: stackName });
  return "deployed";
}

When a wait fails, find the root event with firstFailure() in guides/cloudformation/fix-failed-stack.md.

Quotas

The values aren't typed here; look them up in Service Quotas.

  • Adjustable: stacks per account, StackSets.
  • Not adjustable (the page gives workarounds only):
  • resources per stack: split into nested stacks;
  • template body size: upload to S3, nest, or minify;
  • parameters: use mappings or lists;
  • mappings and outputs;
  • resources per nested-stack operation.

The CDK warns at 80% of the resource limit (reference/cdk/errors.md).

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