CloudFormation
Protocol: Query (XML) — POST http://localhost:4566/ with Action= parameter
Endpoint: POST http://localhost:4566/
Supported Actions
| Action | Description |
|---|---|
DescribeStacks |
Get stack status, parameters, and outputs |
CreateStack |
Deploy a CloudFormation template |
UpdateStack |
Update an existing stack |
DeleteStack |
Delete a stack and its resources |
ContinueUpdateRollback |
Retry the rollback of a stack in UPDATE_ROLLBACK_FAILED, optionally skipping resources or forcing past every failed one (see Failed update rollbacks) |
UpdateTerminationProtection |
- |
CreateChangeSet |
Create a change set |
DescribeChangeSet |
Get change set details with a computed Add/Modify/Remove resource diff |
ExecuteChangeSet |
Apply a change set |
DeleteChangeSet |
Delete a change set |
ListChangeSets |
List change sets for a stack |
DescribeStackEvents |
Get stack creation/update event history |
DescribeStackResources |
Get all resources in a stack |
ListStackResources |
List resource summaries |
GetTemplate |
Retrieve the template body |
GetTemplateSummary |
Summarize a template's Parameters, Resources and Transform sections, by StackName, TemplateBody or TemplateURL |
ValidateTemplate |
Accepted; returns success without validating (stub) |
ListStacks |
List stacks by status |
ListExports |
- |
SetStackPolicy |
Accepted; no-op (stub — stack policies are not enforced) |
GetStackPolicy |
Accepted; returns an empty policy (stub) |
DescribeStackResource |
Get a specific stack resource |
DescribeOrganizationsAccess |
- |
ActivateOrganizationsAccess |
- |
CreateStackSet |
Create a stack set from a template |
DescribeStackSet |
Get stack set details |
ListStackSets |
List stack sets |
UpdateStackSet |
Update the stack set and re-apply to existing instances |
DeleteStackSet |
Delete an empty stack set |
CreateStackInstances |
Provision instances into target accounts/regions |
ListStackInstances |
List instances (optionally filtered by account/region) |
DescribeStackInstance |
- |
DeleteStackInstances |
Remove instances and their resources |
ListStackSetOperations |
List operations performed on a stack set |
DescribeStackSetOperation |
- |
ListStackSetAutoDeploymentTargets |
- |
StackSets compatibility
StackSets support both SELF_MANAGED and the Cloud Launchpad SERVICE_MANAGED workflow. ActivateOrganizationsAccess requires an Organizations management account with all features enabled and enables trusted access for stacksets.cloudformation.amazonaws.com. Service-managed organizational-unit deployment targets are resolved from the caller's actual Organizations state rather than converted into synthetic account IDs. Targeting an OU includes eligible accounts directly in that OU and in all descendant OUs, while excluding the organization management account, matching AWS StackSets targeting semantics.
CreateStackInstances and UpdateStackSet execute the backing CloudFormation stacks in each target account. A failed resource can therefore drive the backing stack through rollback and leave the stack instance INOPERABLE with detailed status FAILED; the StackSet operation is reported as FAILED instead of being forced to success.
Operation IDs are recorded and validated. Duplicate IDs return OperationIdAlreadyExistsException, missing stack sets return StackSetNotFoundException, and missing operation IDs return OperationNotFoundException. Invalid targets and request shapes use the CloudFormation query-protocol validation errors. Operations complete locally, so OperationInProgressException is only reachable when local operation state actually overlaps; Floci does not inject concurrency failures solely to exercise an error code.
CloudWatch Logs log streams
AWS::Logs::LogStream creates a stream in the required LogGroupName. LogStreamName is optional;
when omitted, including through Fn::If returning AWS::NoValue, CloudFormation generates a name
and keeps it across updates. An explicit empty name remains invalid. Ref returns the stream name.
The resource has no Fn::GetAtt attributes.
Changing either name replaces the stream. The previous stream and its events remain available
until the update commits; a failed stack update restores the previous stream. UpdateReplacePolicy:
Retain keeps a displaced stream. Stack deletion removes the current stream and its events, and
tolerates a stream that was already deleted.
CloudWatch Logs metric filters
AWS::Logs::MetricFilter returns the filter name alone for both Ref and
PhysicalResourceId. Floci stores the log group separately for cleanup, including when names
contain |. Mutable updates keep generated names stable.
Changing FilterName or LogGroupName deletes the old filter before creating the replacement.
This works at the 100-filter group limit without temporarily exceeding the quota. The resource's
DELETE and CREATE events precede its final UPDATE event. The
recorded AWS observations also show this ordering
with an already-installed UpdateReplacePolicy: Retain. This is specific to metric-filter
replacement, not a change to ordinary stack DeletionPolicy: Retain.
Rollback restores the complete prior backing definition, not just its reference. A replacement
recreates the deleted filter and receives a new creation time. Failed restoration keeps its
snapshot for retry; a filter absent before the update remains absent after rollback.
That absence is retained as private nonownership metadata: later stack operations cannot adopt
or delete another filter that reuses the same group and name.
Named creates reject an existing filter rather than adopting it through Logs' upsert API.
If storage fails both the write and its ownership inspection, cleanup reports failure rather
than guessing ownership. The snapshot remains available, but an indeterminate surviving filter
requires operator reconciliation before rollback or deletion can finish.
DeleteStack preserves failed-rollback metadata until resource-aware cleanup runs. It removes
confirmed owned restorations or newly created filters whose rollback deletion failed. An
indeterminate outcome keeps the stack in DELETE_FAILED with its metadata available for retry.
CFN mutations record APPLIED, NOT_APPLIED, or UNKNOWN while holding the canonical filter
storage lock, including when storage throws after applying a write or delete. Each group/name
address tracks confirmed ownership, nonownership, or uncertainty. A confirmed delete relinquishes
ownership before another creator can enter, so neither rollback nor a later delete retry can
adopt that creator's filter. Unknown outcomes cannot authorize an upsert or deletion of a
surviving row. Confirmed absence permits safe recovery and finishes account-scoped pending
publication cleanup. Older private rollback flags that cannot establish an outcome are treated
conservatively as unknown.
Baseline snapshots containing logGroupName and filterName are retained as historical metadata,
not replayed as compensation for a new update: that older format could survive a successful
in-place update. Its explicit group/name fields preserve pipe-containing names without ambiguity.
After confirmed absence, a new update creates the requested definition rather than reviving
the stale snapshot.
CloudFormation dimensions use a [{Key, Value}] array, not the Logs API's object shape.
CFN model validation precedes mutation, while provider validation (such as parsing a replacement
filter pattern) can fail after deletion and trigger restoration. The CFN schema allows a
256-character metric namespace, but Floci's Logs API validation currently accepts at most 255:
passing model validation does not imply provider acceptance.
Cognito user pool resource servers
AWS::Cognito::UserPoolResourceServer returns its Identifier for Ref. Changing Identifier
or UserPoolId replaces the server; changing Name or Scopes updates it in place. Optional
Scopes or individual scope entries can be omitted by Fn::If selecting AWS::NoValue.
The provisioner keeps the pool and identifier together in private replacement bookkeeping,
so changing only the pool still cleans up the displaced server without changing the Ref value.
Replacement rollback and historical cleanup use the shared bounded replacement lifecycle.
Provisioning leaves historical cleanup for a committed update or stack deletion. A failed provision
keeps that debt and its remaining retry budget.
Committed replacements honor UpdateReplacePolicy: Retain; failed rollback replacements remain
owed cleanup while their retry budget remains. Exhausted historical records are abandoned across
later updates and stack-delete retries. Historical cleanup is address-based and does not provide
an atomic ownership check against another stack or a direct Cognito API writer reusing the address.
Failed in-place restoration preserves the original name and scopes for a ContinueUpdateRollback
retry. Deleting the current server keeps this snapshot if deletion fails.
SSM parameters
Like AWS's resource handler, AWS::SSM::Parameter is created with one PutParameter that carries
the template's tags and does not overwrite. A name that already exists outside the stack fails the
resource with ParameterAlreadyExists; the stack never overwrites, adopts or deletes that
parameter. Floci applies the Name, Type, Value and Tags properties.
An update that keeps Name overwrites the parameter. When a later resource fails the update, the
rollback writes the prior value and settings back, as a new SSM version when they changed (the
version history is not rewound, as on AWS), and returns the tags the previous or the failed
template set to their prior values; other tags are left alone. As on AWS, the update first checks
that the parameter exists: one deleted outside the stack fails it with ParameterNotFound before
anything is written. A rollback that finds the parameter gone fails the same way, leaving the stack
in UPDATE_ROLLBACK_FAILED.
Giving Name a new value replaces the parameter. The previous parameter stays until the update
commits, and is then deleted unless UpdateReplacePolicy is Retain; a failed update deletes the
replacement instead. A restore or delete that fails during the rollback leaves the stack in
UPDATE_ROLLBACK_FAILED, and ContinueUpdateRollback retries it (see
Failed update rollbacks). Deleting a parameter that is already gone
counts as deleted. Known differences: removing an explicit Name keeps the parameter under that
name, where AWS replaces it with one under a generated name; and an update in place of a parameter
deleted outside the stack ends in UPDATE_ROLLBACK_COMPLETE, since nothing was written, where AWS's
rollback repeats the existence check and likely ends in UPDATE_ROLLBACK_FAILED.
Supported Resource Types
Resource types provisioned during CreateStack / UpdateStack / DeleteStack. Each delegates to
the backing service and sets a real physical ID plus the Ref / Fn::GetAtt attributes used by
cross-resource references.
Adding a type? See Adding a CloudFormation Resource Type. Types live in per-service provisioners under
services/cloudformation/provisioners/. This table is generated from the provisioner inventory bymake docs-sync; edit that, not the table.
| Service | Resource types |
|---|---|
| S3 | Bucket, BucketPolicy (document stored on the bucket; S3 does not evaluate it) |
| SQS | Queue, QueuePolicy (accepted; policy not enforced) |
| SNS | Topic, Subscription, TopicPolicy |
| SES | EmailIdentity (BYODKIM is not supported by this resource; Easy DKIM DNS attributes use the shared emulator signing zone dkim.amazonses.com rather than AWS's region- and identity-specific zone assignment) |
| DynamoDB | Table (TimeToLiveSpecification applied on create and update; to rename an enabled TTL attribute, disable TTL in one update and enable the new attribute in a later one), GlobalTable |
| Lambda | Function (Zip via S3/inline ZipFile, Image, and the hot-reload bind-mount bucket), LayerVersion, EventSourceMapping (SQS, Kinesis, DynamoDB Streams; ParallelizationFactor and TumblingWindowInSeconds are ignored), Version, Alias (also what SAM's AutoPublishAlias expands into), Permission, EventInvokeConfig (also what a SAM function's EventInvokeConfig expands into), MicrovmImage, NetworkConnector, Url, WebFunction (control plane only; the endpoint domain does not serve requests yet), WebFunctionEndpoint (RegionalEndpoints is not exposed to Fn::GetAtt yet), WebFunctionRevision (every property is createOnly, so a change mints a new revision). Inline ZipFile packages include the cfn-response (Node.js) / cfnresponse (Python) module AWS injects for that code path, so Solutions-style custom-resource handlers work. |
| IAM | Role, User (template LoginProfile and PermissionsBoundary are ignored; an API-created login profile is removed on delete), AccessKey, Policy, ManagedPolicy, InstanceProfile |
| Organizations | Organization, OrganizationalUnit, Account, Policy, ResourcePolicy |
| SSM | Parameter |
| KMS | Key, Alias |
| Secrets Manager | Secret, SecretTargetAttachment |
| ECR | Repository |
| ECS | Cluster, TaskDefinition, Service, CapacityProvider, ClusterCapacityProviderAssociations |
| EKS | Cluster, Nodegroup |
| RDS | DBInstance (starts a real container), DBCluster (starts a real container), DBSubnetGroup, DBParameterGroup, DBClusterParameterGroup, DBProxy, DBProxyTargetGroup |
| ElastiCache | CacheCluster (starts a real container; modifying an existing cluster in place is not supported), SubnetGroup, User (Tags are ignored), UserGroup (Tags are ignored), ServerlessCache (GetAtt uses the dotted Endpoint.* and ReaderEndpoint.* form) |
| Redshift | Cluster (single-node container; Port and non-dev DBName ignored; ManageMasterPassword unsupported), ClusterParameterGroup, ClusterSubnetGroup, ClusterSecurityGroup (accepted; no EC2-Classic security group model) |
| Redshift Serverless | Namespace (ManageAdminPassword is accepted and not applied; GetAtt uses the dotted Namespace.* form), Workgroup (starts a real container; one workgroup per namespace; capacity, VPC and price-performance settings are stored only; snapshot restore properties are ignored; GetAtt uses the dotted Workgroup.* form) |
| EC2 | VPC (deleted on stack teardown; a VPC with dependents outside the stack, including anything still holding a network interface in its subnets (an instance that is not terminated, a NAT gateway that is not deleted or failed, a standalone interface, an interface endpoint), fails the delete with DependencyViolation, as on AWS), Subnet, SecurityGroup (inline SecurityGroupIngress/SecurityGroupEgress supported), SecurityGroupIngress, SecurityGroupEgress, InternetGateway, RouteTable, SubnetRouteTableAssociation, Route, NatGateway, EIP, Instance, LaunchTemplate, VPCGatewayAttachment, VPCEndpoint, NetworkAcl, NetworkAclEntry, SubnetNetworkAclAssociation, FlowLog |
| Elastic Load Balancing v2 | LoadBalancer, TargetGroup, Listener, ListenerRule |
| Auto Scaling | LaunchConfiguration, AutoScalingGroup, LifecycleHook, ScalingPolicy |
| Application Auto Scaling | ScalableTarget (ScheduledActions are accepted and not run; Floci has no scheduled scaling), ScalingPolicy |
| Route 53 | HostedZone, RecordSet |
| Cloud Map | HttpNamespace, PrivateDnsNamespace, PublicDnsNamespace, Service |
| API Gateway (v1) | RestApi, Resource, Authorizer, Method, Deployment, Stage, Account, DomainName, BasePathMapping, GatewayResponse, ApiKey, UsagePlan, UsagePlanKey |
| API Gateway v2 | Api, Authorizer, Route, Integration, Stage, Deployment, DomainName, ApiMapping, VpcLink |
| AppSync | GraphQLApi, GraphQLSchema, DataSource, FunctionConfiguration, Resolver, ApiKey. Ref on GraphQLApi and ApiKey returns the id where AWS returns the ARN. See AppSync for Ref and Fn::GetAtt compared with AWS. |
| Step Functions | StateMachine |
| CodePipeline | Pipeline, CustomActionType, Webhook |
| CodeBuild | Project |
| Batch | ComputeEnvironment, JobQueue, JobDefinition |
| Cognito | UserPool (ProviderURL is the local issuer of the tokens Floci mints, <base-url>/<pool id>), UserPoolClient, UserPoolDomain, UserPoolGroup, UserPoolResourceServer, UserPoolUser, UserPoolUserToGroupAttachment |
| ACM | Certificate |
| EventBridge | Rule, EventBus, EventBusPolicy, ApiDestination, Archive (KmsKeyIdentifier is ignored) |
| EventBridge Scheduler | Schedule, ScheduleGroup |
| Transfer Family | Server (management plane only; Ref returns the server ARN; Arn, ServerId and State attributes supported; AS2 managed egress IPs are not modeled; Domain replacement and IdentityProviderType changes are not supported), User (management plane only; Ref returns the user ARN; Arn attribute supported; Policy and PosixProfile are not supported; a ServerId or UserName change replaces the user) |
| Backup | BackupVault |
| GuardDuty | MalwareProtectionPlan (management plane only: no scan runs, so the plan stays ACTIVE; Ref returns the plan id; a BucketName change is rejected) |
| Pipes | Pipe |
| Kinesis | Stream |
| Kinesis Data Firehose | DeliveryStream |
| IoT Core | Authorizer, DomainConfiguration (ServerCertificates resolves to a JSON string), Policy (deleted after detaching it from its principals; on AWS the delete fails with DeleteConflictException while the policy is attached), Thing, TopicRule |
| CloudFront | CachePolicy, Distribution, Function (KeyValueStoreAssociations is ignored), KeyGroup, OriginAccessControl, OriginRequestPolicy, PublicKey, ResponseHeadersPolicy |
| CloudWatch | Alarm, Dashboard |
| CloudWatch Logs | LogGroup, LogStream, MetricFilter |
| WAFv2 | WebACL, WebACLAssociation |
| Config | ConfigRule |
| Bedrock AgentCore | Runtime (Ref returns the AgentRuntimeId; CapacityProviderConfiguration, FilesystemConfigurations, LifecycleConfiguration, PlatformVersion and RequestHeaderConfiguration are accepted and not stored), RuntimeEndpoint (Ref returns the endpoint ARN; Tags are accepted and not stored), Memory (Ref returns the memory ARN; MemoryStrategies, IndexedKeys, NamespaceKeys and StreamDeliveryResources are accepted and not stored) |
| CloudFormation | CustomResource, Custom::DynamoDBReplica (applied natively against DynamoDB, not via a provider Lambda), Stack (nested stacks), Custom::* (Lambda-backed) |
| CloudTrail | Trail |
| CDK | CDK::Metadata (accepted; no-op) |
All other resource types are accepted without error and assigned a synthetic physical ID (with an
arn:aws:stub:::<logicalId> ARN attribute), so templates with unsupported types still reach
CREATE_COMPLETE rather than failing. Nothing is created for such a resource, so each one is
logged at WARN and carries a resource status reason saying so, which DescribeStackEvents
returns:
Resource type AWS::Fake::Thing is not supported by Floci. It was stubbed and nothing was created for it.
Set floci.services.cloudformation.allow-stub-unsupported-resource-types to false
(FLOCI_SERVICES_CLOUDFORMATION_ALLOW_STUB_UNSUPPORTED_RESOURCE_TYPES=false) to fail such a
resource instead: it reaches CREATE_FAILED and the stack rolls back. Use it in a pipeline that
must not pass over a resource it never got.
SES Email Identities
AWS::SES::EmailIdentity provisions an SES identity and supports in-place option updates and
replacement when EmailIdentity changes. Change-set previews also mark the replacement and its
Ref dependents.
If an update rollback cannot restore the identity snapshot, the stack remains in
UPDATE_ROLLBACK_FAILED. ContinueUpdateRollback retries the restoration; UpdateStack is
rejected until rollback completes. A successful retry permits later updates. DeleteStack can
delete the current managed identity without first restoring its snapshot.
Cleanup keeps displaced-identity records while deletion attempts remain. After three cleanup
attempts, an exhausted entry is removed from stack management and a later DeleteStack does not
retry it. Committed update cleanup uses the same three-attempt limit.
EventBridge Scheduler Schedules
AWS::Scheduler::Schedule creates a real schedule. Ref returns its name and Fn::GetAtt Arn
returns its ARN. A group move preserves the name, removes the old group address, and restores the
original configuration if the stack update rolls back.
Fn::If values that select AWS::NoValue omit optional schedule properties and nested target
or time-window fields. ScheduleExpression, Target, FlexibleTimeWindow, and their required
fields still must be present and valid.
Floci uses its main engine's bounded replacement-cleanup policy for committed updates and
DeleteStack: each displaced address has up to three cleanup attempts, and exhausted entries are
dropped. A failed cleanup leaves the first stack deletion in DELETE_FAILED, even if the current
schedule was deleted; a later retry does not retry the dropped addresses. Schedules left after
exhausted cleanup require manual deletion through the Scheduler API. A failed current-schedule
delete preserves pending recovery state for a later deletion retry. This is Floci's shared cleanup
policy, not a claim that AWS guarantees three attempts for DeleteStack.
UpdateReplacePolicy: Retain keeps a name replacement's old schedule, but does not keep a group
move's old address or an orphan created by a failed update.
Schedules are addressed by group and name, as in the Scheduler API. If another client removes a managed schedule and recreates the same address, an in-place stack update applies the template to the current schedule there. Stack deletion and replacement cleanup delete the current schedule at a tracked address, and rollback restores its saved configuration at that address. A historical cleanup entry with attempts remaining can still affect a new occupant of its address. Dropping exhausted debt prevents later retries, but does not establish resource ownership.
EventBridge Event Buses
AWS::Events::EventBus creates a real custom EventBridge bus. Name is required, Ref returns
the bus name, and Fn::GetAtt supports Arn and Name. Description and Tags are applied when
the bus is created. Rules that reference the bus are removed before stack deletion.
The current implementation is limited to custom buses with the Name, Description, Tags, and
Policy properties. EventSourceName, KmsKeyIdentifier, DeadLetterConfig, and LogConfig are
rejected with ValidationError instead of being silently ignored. AWS models a Name change as
resource replacement; Floci currently rejects that update until generic replacement handling is
available. Policy is applied when the bus is created. Changing Description, Tags, or Policy
during UpdateStack is rejected until transactional resource rollback is available; this prevents a
failed stack update from leaving the live bus in the rejected configuration.
EventBridge archives
AWS::Events::Archive creates a real archive of the events sent to SourceArn, which must be an
existing event bus in the stack's account and region, as CreateArchive requires. ArchiveName is
optional; when omitted, CloudFormation generates a name and keeps it across updates. Ref returns
the archive name and Fn::GetAtt Arn the archive ARN. A missing RetentionDays stores 0, and an
EventPattern object reads back from DescribeArchive as a compact JSON string.
KmsKeyIdentifier is ignored. A Description over 512 characters, an EventPattern over 4096, or a
negative RetentionDays fails the resource with the CreateArchive or UpdateArchive validation
message, as on AWS.
Changing Description, EventPattern, or RetentionDays updates the archive in place. A property
removed from the template is not sent, so the archive keeps its previous value, as on AWS. Changing
SourceArn or ArchiveName, or dropping an explicit ArchiveName, replaces the archive: the new
archive is created during the update and the previous one is deleted once the update commits. A
replacement that keeps the same explicit ArchiveName, or declares the generated name explicitly,
fails with CloudFormation's custom-named resource error and leaves the archive unchanged. Stack
deletion removes the archive and tolerates one that was already deleted.
Secrets Manager Target Attachments
AWS::SecretsManager::SecretTargetAttachment adds the target's database connection fields to the
referenced secret while preserving credentials and custom fields. Ref and Fn::GetAtt Id return
the complete secret ARN, only one attachment can own a secret, and deleting the attachment removes
only its managed connection fields.
Supported target types are:
AWS::RDS::DBInstanceAWS::RDS::DBClusterAWS::DocDB::DBInstanceAWS::DocDB::DBCluster
Redshift clusters, Redshift Serverless namespaces, and DocumentDB Elastic clusters are not supported
because their backing services are not implemented. A SecretId change is applied in place rather
than reproducing CloudFormation's replacement event sequence; failed changes restore affected secret
data and attachment ownership.
Organizations
AWS::Organizations::Organization uses the stack's calling account as the management account, so
the rest of the stack's Organizations resources are provisioned into that account's organization.
Fn::GetAtt Org.RootId is the usual way to root the OU tree in the same template. Organization is
the one type in this section where bare Ref does not return the resource's own id: per AWS, Ref
returns the management account id, while Fn::GetAtt Org.Id returns the organization id.
OrganizationalUnit—ParentIdis create-only per the registry schema, so an update only renames the OU in place; the physical id survives, keeping everyRefto it valid.Account—ParentIdsaccepts a single entry and the account is moved there after creation (accounts are always created under the root). Because Floci resolves a 12-digit access key id straight to an account,Ref/Fn::GetAtt AccountIdyields an id you can immediately use as a caller identity against other services.StatemirrorsStatus, the parameter AWS is retiring it in favour of; Floci does not model thePENDING_ACTIVATIONorCLOSEDphases that onlyStatecan express.Policy—TargetIdsis reconciled on update: targets the template adds are attached and ones it drops are detached. Deleting the resource detaches its remaining targets first, sinceDeletePolicyrefuses while a policy is still attached.ResourcePolicy— backed byPutResourcePolicy, which is already create-or-update.
Fn::GetAtt OrganizationalUnit.Path and Fn::GetAtt Account.Paths return the organization path —
o-<org>/r-<root>/[ou-<ou>/…]<id>/. An account has one parent and therefore one path, so the
list-typed Paths holds a single entry; read it with Fn::Select as you would on AWS.
Deleting the stack removes the resources in dependency order and finally the organization itself. Deleting a resource that is already gone is tolerated.
Auto Scaling Launch Template Resolution
AWS::AutoScaling::AutoScalingGroup resolves its launch template through any of the shapes AWS
accepts, not only by name:
LaunchTemplatewithLaunchTemplateIdorLaunchTemplateName(plus an optionalVersion). The id and name are distinct lookup keys, so anlt-id is matched as an id rather than being treated as a name.- A
Refto an in-stackAWS::EC2::LaunchTemplate, whoseRefreturns thelt-id and whoseFn::GetAtt LatestVersionNumbersupplies the version. MixedInstancesPolicy→LaunchTemplate→LaunchTemplateSpecification, includingOverrides[].InstanceTypeandInstancesDistribution(OnDemandBaseCapacity,OnDemandPercentageAboveBaseCapacity,SpotAllocationStrategy). A non-integer where AWS expects a number fails the stack rather than being dropped.Overrides[].WeightedCapacityis carried through as well.
The group also passes ServiceLinkedRoleARN, InstanceMaintenancePolicy,
AvailabilityZoneDistribution and CapacityReservationSpecification through to the group, with
the same validation the Auto Scaling API applies. The resource schema requires
CapacityReservationPreference on CapacityReservationSpecification and Granularity on each
MetricsCollection entry. MetricsCollection enables the listed metrics (an entry naming none
enables all of them), and on UpdateStack the group's enabled metrics are
set to exactly what the template lists. Removing the property leaves collection as it was.
Updates With Nothing to Change
An UpdateStack that changes none of the stack's resources and outputs is refused with
ValidationError No updates are to be performed. and changes nothing, as on AWS. What is compared
is what CloudFormation compares (measured on AWS): of each active resource its Type, Properties,
Metadata, DeletionPolicy, UpdateReplacePolicy and UpdatePolicy, and of each active output its
Value, Description and Export, with whatever does not depend on a resource resolved first:
parameters, mappings, conditions, pseudo parameters, and dynamic references, whose stored value is
compared with the one the stack was deployed with. A literal written as Fn::Join, a parameter
written as Fn::Sub, or an Fn::If whose other branch changed is therefore no change, while a used
mapping value, a used AWS::SSM::Parameter::Value parameter whose stored value moved, or a dynamic
reference whose value moved is. A Ref or Fn::GetAtt of a resource, Fn::ImportValue and
Fn::GetStackOutput are compared as written. A new Description, template Metadata or Rules,
an unused parameter, mapping or condition, a DependsOn, a CreationPolicy, or an output whose
condition is false is not an update; tags that differ from the stack's are, and a template with a
nested stack is always updated, since its child template is read again. The template is processed
as CloudFormation processes it: AWS::Include fragments are read again and merged and the SAM
transform is applied with the stack's parameter values. The same comparison decides which resources
a change set modifies.
What each dynamic reference resolved to is kept on the stack when an operation completes, as an HMAC-SHA256 under a random key of the stack's own, so no resolved value is stored. An update that fails and rolls back keeps the values of the last deployment. A stack set instance whose stack has nothing to change is left as it is and succeeds, and the change set that found it so is not kept.
A CreateChangeSet for such an update is created FAILED, UNAVAILABLE, with The submitted
information didn't contain changes. Submit different information to create a change set., which is
what the AWS CLI's deploy and the CDK read as "no changes".
The CDK then deletes that change set, and before its next deploy deletes it again by name. A
DeleteChangeSet for a change set the stack does not have succeeds, as on AWS, whatever the stack's
status, named with its stack or by its ARN alone; a StackName that names no stack is still a
ValidationError.
Lambda Stack Updates
AWS::Lambda::Function resources are reconciled during UpdateStack in the same shape as CloudFormation/CDK deployments:
- A no-op redeploy keeps the existing physical function name and does not call Lambda update APIs, so warm containers can be reused.
- Code and mutable configuration changes update the existing function in place.
- Replacement-only changes such as
FunctionNameorPackageTypechanges create a replacement function and remove the old one. - A changed
DurableConfigupdates the function in place. ARetentionPeriodInDaysthe template leaves out goes back to 14, and aKMSKeyArnit leaves out is cleared. Adding or removingDurableConfigreplaces the function, since Lambda cannot do either in place. A durable function created withoutTimeoutgetsmin(ExecutionTimeout, 900), while an update without it sets 3, as on AWS. - S3-backed code stays linked through
S3Bucket/S3Key, so Lambda's reactive S3 sync continues to work for functions created by CloudFormation or CDK. - Hot-reload code (
S3Bucket: hot-reload) is compared by host path: the same path is a no-op, a different path updates the bind mount in place. Tagsare applied when the function is created, including a replacement function. OnUpdateStackthe template's tags are applied and only the keys the previous template set and the new one drops are removed, so a tag added outside the template is kept, as in AWS.
SAM published aliases
AutoPublishAlias creates a version and points the generated alias at that version's
numeric Version attribute. CloudFormation resolves the version before creating the
alias. As in SAM, the version's logical id is <Function>Version followed by ten hex digits of a
SHA-1 over the function's code, with its template parameter references resolved (pseudo
parameters such as ${AWS::Region} stay as written), its Environment and MemorySize as
written, and its SnapStart when it sets an ApplyOn other than None. An update that changes the
code, Environment or MemorySize, or a parameter the code uses, publishes a new version and
moves the alias to it. A parameter used only in Environment or MemorySize does not, and neither
does a property outside the hash, such as Timeout. A new id publishes only when the function's
code or configuration changed since its last version. floci does not give the function
SnapStart, so turning it on changes the id but publishes nothing: the alias stays where it is.
The version a new id replaces stays published: like SAM, floci gives the version
DeletionPolicy: Retain unless the function sets a DeletionPolicy, and the update reports it
DELETE_SKIPPED. With Delete floci reports the old version DELETE_COMPLETE but never deletes
it, where AWS does. Changes made to $LATEST outside the stack, including Lambda's reactive S3
sync, do not reach the alias until an update publishes a new version. Event sources and API
integrations still invoke the function rather than the alias, so they run $LATEST.
RDS Credential Dynamic References
AWS::RDS::DBInstance and AWS::RDS::DBCluster resolve CloudFormation dynamic
references in MasterUsername and MasterUserPassword during resource creation:
secretsmanagerreferences support whole secret strings, JSON keys, version stages, and version IDs.ssmreferences acceptStringandStringListparameters, using either the latest value or an explicit positive version.ssm-securereferences require aSecureStringparameter and are supported only forMasterUserPassword, matching the AWS resource-property allowlist.
Dynamic-reference expansion is currently scoped to these RDS credential properties.
RDS Associated Roles
AWS::RDS::DBCluster and AWS::RDS::DBInstance apply AssociatedRoles through the same checks as
AddRoleToDBCluster / AddRoleToDBInstance (see RDS IAM role associations):
Fn::Ifmay select the whole list or a single entry, andAWS::NoValueleaves it out. A value that is not a list of roles is aValidationError.- On create, the roles are associated with the new cluster or instance. A list RDS refuses (a missing
RoleArn, an instance role withoutFeatureName, or a cluster role named twice) fails the resource, and the new database is deleted again. As in AWS, an instance role or feature the list repeats is skipped, not refused. A renamed instance keeps its predecessor until the new one has its roles. - On
UpdateStack(no interruption, as in AWS), a cluster's list is checked first, then the roles the template gained are added, and the roles the previous template declared and the new one drops are removed. A role associated outside the stack is kept while the template leaves it out; declaring it fails the update withDBClusterRoleAlreadyExists, as in AWS. If any step of an update is refused, the roles it already added are removed and the ones it removed are put back, so the database matches what the stack still records and a retry starts from there. A rolled-back cluster replacement restores the record of which roles the stack declared. - An Aurora cluster member (
AWS::RDS::DBInstancewithDBClusterIdentifier) cannot carryAssociatedRoles: the schema documents the property as not applicable there, since the cluster manages its roles. The resource fails with aValidationErrorpointing at the cluster'sAssociatedRoles.
Account-Aware Provisioning
Resources provisioned by CreateStack / UpdateStack land in the caller's account namespace
(determined from the request's access key — see Multi-Account Isolation).
Deleting the stack removes them from that same account.
Stacks, change sets, and exports are scoped to the caller account. ListExports returns only the
exports created by that account's stacks, and Fn::ImportValue resolves against the same account's
export table — so two accounts can each own an export with the same name without colliding, mirroring
how CloudFormation isolates exports per account and region. This is what lets a multi-account LZA
deployment reuse identical export names across its member accounts.
Stack Output References (Fn::GetStackOutput)
Fn::GetStackOutput reads an output of another stack, which needs no Export. It is what the CDK
synthesizes for a weak cross-stack reference. The value is read when the consuming resource is created
or updated. Floci follows what CloudFormation does, measured against it, where that departs from the
intrinsic's reference page:
StackNameandOutputNameare required;Regiondefaults to the consuming stack's Region, andRoleArnnames a role in the account that owns the referenced stack. A key the function does not define is ignored.- A parameter value may use any intrinsic function, including a
ReforFn::GetAttto a resource of the same stack,Fn::ImportValueand anotherFn::GetStackOutput; it resolves like any property. A dynamic reference is not resolved there, one inside anFn::Subvariable map included: the stack name reaches DescribeStacks as written and fails its name constraint (1 validation error detected: Value '{{resolve:ssm:...}}' at 'stackName' failed to satisfy constraint: ...), as on AWS. - A referenced stack that does not exist fails the resource with DescribeStacks'
ValidationError(Stack with id X does not exist (Service: AmazonCloudFormation; ...)), and an output that does not exist withTemplateError: Fn::GetStackOutput references output O from stack S, but this output was not found. The output may have been deleted.The reference never resolves to an empty string. - A
Regionthat is not a Region fails withTemplateError: Region R in Fn::GetStackOutput is not a valid AWS region., and one of another partition withInvalidClientTokenId, as the call to it does. - A
RoleArnthat is not an ARN fails withTemplateError: Invalid RoleArn parameter X in Fn::GetStackOutput. Any other ARN that is not an existing role (a user, a role of another partition, a role that does not exist) fails with STS'sAccessDenied, naming the account's root as the caller. On AWS the role is assumed by the stack's execution role, or without one by the caller of the stack operation, and the outputs are read with DescribeStacks in a session namedGetStackOutput; the CDK's role trusts the consuming account's execution role. Floci runs stack operations under no execution role and keeps no caller for them. With IAM enforcement off, asAssumeRole, it evaluates neither the role's trust policy nor its permissions. With enforcement on, the trust policy has to allow a principal in the consuming account (its root, or any principal of it the policy names, such as the CDK's execution role), or STS'sAccessDeniedfails the resource, and the role's policies have to allowcloudformation:DescribeStackson the stack, or DescribeStacks'AccessDenieddoes (User: arn:aws:sts::A:assumed-role/R/GetStackOutput is not authorized to perform: cloudformation:DescribeStacks on resource: ... because no identity-based policy allows the cloudformation:DescribeStacks action). - Arguments that are not a map, or that lack
StackNameorOutputName, are refused when the stack operation is requested, withValidationErrorTemplateError: Fn::GetStackOutput requires a map of named parametersorGetStackOutput: StackName is required, as on AWS. - An output whose
Conditionis false is never read, so one naming a stack that does not exist leaves the operation complete; like any output whose condition is false, it is not listed. - It resolves inside an
Fn::Subvariable map, insideFn::Base64and as a directOutputsvalue, which the reference page lists as not supported yet. An output that cannot be read fails the operation once the resources exist, and the stack rolls back. Anywhere inConditions, and insideFn::ImportValue, the stack operation is refused when it is requested, withValidationError,AWS::Includefragments included; in an output'sExport.Nametoo, withTemplate format error: Output O is malformed. The Name field of Export must not depend on any resources, imported values, or Fn::GetAZs.In a nested stack's template the same rules fail the child's resource with the same message when the child is created, and the parent rolls back.
Template Parameters
Parameters passed to CreateStack / UpdateStack (and echoed back by DescribeStacks) are resolved
before provisioning:
String,Number,CommaDelimitedList, andList<...>parameter types are accepted and substituted into resource properties viaRef.AWS::SSM::Parameter::Value<String>-typed parameters are resolved at deploy time: the value the caller supplies is treated as an SSM parameter name, and floci substitutes the current value of that SSM parameter into the template. This is the pattern CDK uses to pull bootstrap values (image tags, bucket names) from Parameter Store.AWS::SSM::Parameter::Value<List<String>>andAWS::SSM::Parameter::Nametyped parameters are not yet resolved — they are passed through as their literal input.- A declared parameter needs a value. One that the request gives no value and the template no
DefaultfailsCreateStack,UpdateStackandCreateChangeSetwithValidationErrorParameters: [Env] must have values, naming each such parameter, before anything changes. An empty value counts as a value. An update does not carry values over: setUsePreviousValueto keep the deployed one.UsePreviousValueon a parameter that has no deployed value passes none. The values are checked before the template's dependency checks (a cycle, an unresolved dependency, a malformed condition), which read them, so a template with a cycle and a missing value gets this error. A request for a stack that does not exist, cannot be updated, or already exists gets that stack error instead of this one; a dependency error still comes before the stack error. The same check refusesCreateStackSetandUpdateStackSet, and fails a nested stack's resource whoseParametersleave a child parameter without a value. A parameter that anAWS::Includedefines is not checked, nor is any parameter in a section that carries anAWS::Includeof its own.
The AWS::SSM::Parameter resource type exposes Value, Type, Name, and Arn attributes through
Ref / Fn::GetAtt so downstream resources can consume a parameter the same stack creates.
Tags are applied when the parameter is created. On UpdateStack the template's tags are applied and
only the keys the previous template set and the new one drops are removed, so a tag added outside the
template is kept, as in AWS.
AWS::Include (Fn::Transform)
Fn::Transform with Name: AWS::Include splices the YAML/JSON snippet at Parameters.Location
into its enclosing mapping before any other intrinsic resolves, on both CreateStack/UpdateStack
and the CreateChangeSet preview. Location must be an s3://bucket/key URI: the template
CloudFormation itself receives always carries one, because aws cloudformation package rewrites
every local path before a stack ever sees it. A Location that is not s3:// fails the stack with
a ValidationError naming it, rather than silently dropping the include. A Location that is a
well-formed s3:// URI but cannot be read (the bucket or key does not exist) fails the stack with
the underlying S3 error naming it, for example NoSuchKey at HTTP 404, instead of a
ValidationError, since that error is what S3 itself already reports and floci has no more specific
answer to give.
A snippet may not itself use AWS::Include; nesting is rejected rather than expanded or looped.
Location must be a plain string; a Ref or another intrinsic in its place is rejected, naming
the rejected node, rather than resolved.
Two known deviations from AWS:
- The snippet is parsed with floci's CloudFormation-aware YAML parser, so it accepts CloudFormation
YAML short tags (
!Ref,!Sub, ...) where AWS's ownAWS::Includedocumentation says a snippet does not. - AWS's own
Fn::Transformdocumentation shows aLocationwritten as an intrinsic function (its example usesRef) and describes it as accepted; floci does not resolve one and rejects the template instead. This deviation comes from reading AWS's documentation, not from a request measured against a real account.
CAPABILITY_AUTO_EXPAND is not one of them. floci requires no capability for a template that
declares AWS::Include, and neither does AWS on the change-set path: a CreateChangeSet carrying
an embedded Fn::Transform/AWS::Include was accepted against a real account with
CAPABILITY_IAM alone. The CreateStack path was not measured.
GetTemplateSummary does not expand the include: it reports AWS::Include in the template's
Transform/DeclaredTransforms and neither fetches nor validates the snippet, matching AWS.
GetTemplate accepts TemplateStage (Original, the default, or Processed) and validates it
against that enum, rejecting anything else with a ValidationError naming the value, matching AWS.
Original returns the template exactly as submitted, Fn::Transform node and all. Processed
returns the merged and SAM-expanded tree, the same one a CreateChangeSet preview diffs against.
floci expands neither AWS::LanguageExtensions, nor a third-party macro, nor the top-level
Transform: {Name: AWS::Include, Parameters: {Location: ...}} form. A template carrying only one of
those three keeps Processed equal to Original, byte for byte.
Two triggers break that equality, because executeTemplate re-serializes the persisted body when
either one fires: an embedded Fn::Transform that merges, and a SAM transform. A SAM transform goes
further, because SamTransformProcessor removes the whole Transform section unconditionally, so a
macro co-declared beside SAM is absent from Processed as well.
Real AWS's answer for these shapes is unmeasured, co-declared with SAM or not. StagesAvailable
always lists both stages, matching AWS.
Conditions
Template Conditions are evaluated before provisioning. A resource whose Condition evaluates to
false is skipped — it is never provisioned, does not appear in DescribeStackResources, and its
Ref / Fn::GetAtt are not required to resolve. This matches CloudFormation and is required for the
condition-heavy templates CDK and LZA emit.
The operands of Fn::Equals are resolved as resource property values are, so Ref to a parameter
or a pseudo parameter (AWS::StackName and AWS::StackId included) and Fn::FindInMap, the
functions CloudFormation supports there, work inside a condition. The dependency check a create runs
before the stack exists sees the AWS::StackId the stack is then given. An operand Floci cannot
resolve compares as an empty string. AWS::NotificationARNs is the empty list everywhere, as
Floci keeps no notification ARNs. Fn::ImportValue is not allowed in a condition, as in CloudFormation: CreateStack,
UpdateStack and CreateChangeSet refuse such a template, with the message Template error: Cannot
use Fn::ImportValue in Conditions. A SAM template's change set fails with that reason instead, and
so does the stack when CreateStack or UpdateStack executes it; an AWS::Include template fails when
it is executed.
Custom Resources and the CDK Provider Framework
AWS::CloudFormation::CustomResource and Custom::* resources are backed by their ServiceToken
Lambda. floci supports two shapes:
- Direct custom resources — floci invokes the handler Lambda with the CloudFormation custom-resource
event and waits for it to
PUTitsSUCCESS/FAILEDresult to the response URL. InlineZipFilehandlers get thecfn-response/cfnresponsemodule bundled in (see the Lambda row in Supported Resource Types), so Solutions-style handlers work unmodified. The event'sStackIdis the id of the stack that contains the resource, the valueRef AWS::StackIdreturns andDescribeStacksreports, onCreate,UpdateandDeletealike. In a nested stack it is the nested stack's own id. - CDK Provider framework — when the
ServiceTokenpoints at a CDKframework.onEventfunction, floci drives the asynchronous provider protocol:onEventstarts the work andframework.isCompleteis polled (via Step FunctionsRetry) until it reports done, at which point the ResponseURL callback fires. The wait is bounded by an async custom-resource timeout (3 minutes by default); a resource that never completes fails the stack rather than hanging.
The handler's Data keys resolve through Fn::GetAtt, except keys that begin with __Floci. Floci
reserves that prefix for its own resource state and ignores such keys.
A failed stack update rolls back a custom resource whose handler was sent an Update, as
CloudFormation does. This holds whether the handler applied the update and a later resource failed,
or the handler answered FAILED itself. The handler is sent a second Update under the same
PhysicalResourceId, with the old properties as ResourceProperties and the attempted ones as
OldResourceProperties, so it can undo the change. A handler that answers FAILED to that rollback
leaves the resource UPDATE_FAILED with its Reason, and the stack UPDATE_ROLLBACK_FAILED. The
old properties still become the resource's own, as on AWS: a later DeleteStack sends them in its
Delete, and the next update sends them as OldResourceProperties. An update whose handler returned
a new PhysicalResourceId replaced the resource. Its rollback sends no Update: the new id gets a
Delete with the attempted properties, and the resource goes back to the old id. CloudFormation sends
that Delete in its UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS phase. Floci has no rollback
cleanup phase and sends it during the rollback. As in that phase, a Delete the handler fails is
logged and does not fail the rollback. When the rollback's own Update returns a new id, the id it
was sent gets a Delete straight away for the same reason. An update that changes ServiceToken
reaches no handler: it fails with Modifying service token is not allowed., as on AWS, and its
rollback sends nothing.
Failed update rollbacks
When an update fails, Floci rolls back the resources it changed. A resource whose rollback fails
is left UPDATE_FAILED, and the stack settles in UPDATE_ROLLBACK_FAILED. As on AWS, UpdateStack
and an UPDATE change set are then refused with ValidationError (Stack:<arn> is in
UPDATE_ROLLBACK_FAILED state and can not be updated.). Two ways out remain:
DeleteStackdeletes the stack and its resources, theUPDATE_FAILEDones included (see Deletion Policies).ContinueUpdateRollbackruns the rollback again for the resources still owed one, starting with anUPDATE_ROLLBACK_IN_PROGRESSstack event whose reason isUser Initiated. A retry re-runs the restore of each resource still owed one, including the delete of a replacement whose earlier delete failed; a resource whose restore cannot be redone fails again, leaving the stack inUPDATE_ROLLBACK_FAILED, and can be passed inResourcesToSkip.ResourcesToSkipnamesUPDATE_FAILEDresources to report asUPDATE_COMPLETEwith the reasonResource skipped during UpdateRollback, without rolling them back; a skipped resource keeps the state the failed update left it in. Once every other resource rolled back, the stack reachesUPDATE_ROLLBACK_COMPLETEwith the template, parameters and outputs from before the failed update, and takes updates again.
ForceRollback=true skips every UPDATE_FAILED resource of the stack, each reported as a
ResourcesToSkip skip is. When a forced rollback skipped a resource and completes, the stack's
StackStatusReason and the reason of its UPDATE_ROLLBACK_COMPLETE event are One or more
resources were skipped during UpdateRollback. These resources were not rolled back and may have
drifted from the template. Run drift detection (DetectStackDrift) to review their current state
before your next update. A rollback completed with ResourcesToSkip has no stack reason, as on
AWS.
As on AWS, a malformed ContinueUpdateRollback is refused with ValidationError before the stack
is looked up, listing every violation: a StackName that is missing, empty, or does not match
[a-zA-Z][-a-zA-Z0-9]*|arn:[-a-zA-Z0-9:/._+]*, and a ResourcesToSkip member that does not
match [a-zA-Z0-9]+|[a-zA-Z][-a-zA-Z0-9]*\.[a-zA-Z0-9]+. ForceRollback=true with a non-empty
ResourcesToSkip is then refused with ForceRollback and ResourcesToSkip are mutually exclusive,
a stack that does not exist with Stack: <StackName> does not exist, and a stack in any status
other than UPDATE_ROLLBACK_FAILED with RollbackUpdatedStack cannot be called from current stack
status. ResourcesToSkip is checked against the stack after the call is accepted: a skip that is
not a resource of the stack, or not UPDATE_FAILED, returns the stack to UPDATE_ROLLBACK_FAILED
with the reason, touching no resource, and a later call can still finish the rollback. RoleARN
and ClientRequestToken are accepted and have no effect.
Known difference: ResourcesToSkip does not support a nested stack's resource
(NestedStackName.ResourceLogicalID). When the prefix names a nested stack of the stack, the
rollback fails again with a reason saying Floci does not support it, where AWS would skip that
resource.
A stack that reached UPDATE_ROLLBACK_FAILED under an earlier Floci version kept no record of its
state before the update. ContinueUpdateRollback then retries every UPDATE_FAILED resource and
keeps the template the stack holds.
Deleted Stacks
A deleted stack is kept for a short window afterwards rather than being forgotten at
DELETE_COMPLETE, because the client that asked for the delete goes on polling for it. Within that
window AWS's asymmetry is reproduced:
DescribeStacksby stack id (the ARN) answers with the stack, itsDELETE_COMPLETEstatus and itsDeletionTime.DescribeStackEventsby stack id answers likewise.DescribeStacksby name returnsValidationError, as it does on AWS. The CDK CLI depends on the pair: it monitors a delete by stack id, and a stack id that stops resolving ends the rest of acdk destroy --allrun.ListStacksincludes the stack asDELETE_COMPLETEwith itsDeletionTime, and aStackStatusFilterofDELETE_COMPLETEselects it. A name reused after a delete is listed twice, once per stack id.
Once the window passes, all of those behave as though the stack had never existed. AWS keeps a deleted stack for 90 days; locally it only has to outlive the delete polling of the client that asked for it, so the window defaults to 30 seconds (see Configuration).
Deletion Policies
A resource's DeletionPolicy
attribute is honored on DeleteStack, on the rollback of a failed CreateStack, and when an
update removes the resource from the template, where it applies as on DeleteStack:
| Value | DeleteStack |
Rollback of the create that made the resource |
|---|---|---|
Delete (default) |
deleted | deleted |
Retain |
kept | kept |
RetainExceptOnCreate |
kept | deleted |
A kept resource is reported as DELETE_SKIPPED in DescribeStackEvents and does not fail the
deletion — the stack still reaches DELETE_COMPLETE while the resource keeps existing. This also
lets a stack owning a non-empty S3 bucket be deleted, since the bucket is never touched.
Otherwise DeleteStack deletes each resource that has a physical id and is in one of these
statuses:
CREATE_COMPLETE,UPDATE_COMPLETEUPDATE_FAILED, which a failed update rollback leaves on the resources it could not restore, so deleting a stack inUPDATE_ROLLBACK_FAILEDremoves themDELETE_FAILED, which a retriedDeleteStackattempts againCREATE_FAILED, only when the stack created the backing entity, since a failed create can name an entity that existed before and belongs to someone else
Resources in any other status (DELETE_COMPLETE, DELETE_SKIPPED, an in-progress status) and
resources without a physical id are skipped. A resource that cannot be deleted leaves the stack in
DELETE_FAILED, named in the status reason.
Deviations from AWS to be aware of:
Snapshotdeletes the resource without taking a snapshot; floci has no snapshot support for the types AWS allows it on.- Every resource defaults to
Delete. AWS instead defaultsAWS::RDS::DBCluster, andAWS::RDS::DBInstancewithout aDBClusterIdentifier, toSnapshot. - Unrecognized values are treated as
Delete. - After
DeleteStackcompletes, a retained resource'sDELETE_SKIPPEDrecord is only visible throughDescribeStackEventsfor the deleted stack, notDescribeStackResources. UpdateReplacePolicyis honored only by the resource types that delete a displaced resource once the update commits, such as an SSM parameter or a log stream; other types keep the displaced resource, or delete it during the update, whatever the policy. TheRetainExceptOnCreaterequest parameter ofCreateStack/UpdateStackis not implemented.
StackSets
StackSets deploy a single template into many target accounts and regions:
export AWS_ENDPOINT_URL=http://localhost:4566
# 1. Create the stack set (in the administration account)
aws cloudformation create-stack-set \
--stack-set-name my-set \
--template-body file://template.yml \
--endpoint-url $AWS_ENDPOINT_URL
# 2. Create instances in two target accounts
aws cloudformation create-stack-instances \
--stack-set-name my-set \
--accounts 222222222222 333333333333 \
--regions us-east-1 \
--endpoint-url $AWS_ENDPOINT_URL
# 3. The resources materialize in each target account's namespace
aws cloudformation list-stack-instances \
--stack-set-name my-set \
--endpoint-url $AWS_ENDPOINT_URL
CreateStackInstances drives the single-stack engine once per (account, region) pair, provisioning
each instance's resources into that target account's namespace — so a queue named orders deployed
into accounts 222222222222 and 333333333333 exists independently in each. The stack set, its
instances, and its operation history are recorded in the administration (caller) account.
DeleteStackInstances removes instances and their resources, unless RetainStacks=true, which
detaches the instances from the stack set but leaves their underlying stacks and resources in place.
A stack set must be empty before DeleteStackSet.
A CreateStackInstances / UpdateStackSet operation reports FAILED if any of its instances fails
to deploy (the instance is marked INOPERABLE), so polling DescribeStackSetOperation reflects real
provisioning outcomes rather than always returning SUCCEEDED.
Configuration
| Variable | Default | Description |
|---|---|---|
FLOCI_SERVICES_CLOUDFORMATION_ENABLED |
true |
Enable or disable the service |
FLOCI_SERVICES_CLOUDFORMATION_DELETED_STACK_RETENTION_SECONDS |
30 |
How long a deleted stack stays describable by its stack id and listed as DELETE_COMPLETE (see Deleted Stacks) |
Examples
export AWS_ENDPOINT_URL=http://localhost:4566
# Validate a template
aws cloudformation validate-template \
--template-body file://template.yml \
--endpoint-url $AWS_ENDPOINT_URL
# Deploy a stack
aws cloudformation create-stack \
--stack-name my-stack \
--template-body file://template.yml \
--parameters ParameterKey=Env,ParameterValue=dev \
--endpoint-url $AWS_ENDPOINT_URL
# Check status
aws cloudformation describe-stacks \
--stack-name my-stack \
--endpoint-url $AWS_ENDPOINT_URL
# Watch events
aws cloudformation describe-stack-events \
--stack-name my-stack \
--endpoint-url $AWS_ENDPOINT_URL
# Update
aws cloudformation update-stack \
--stack-name my-stack \
--template-body file://template.yml \
--endpoint-url $AWS_ENDPOINT_URL
# Delete
aws cloudformation delete-stack \
--stack-name my-stack \
--endpoint-url $AWS_ENDPOINT_URL
# Create a change set
aws cloudformation create-change-set \
--stack-name my-stack \
--change-set-name my-change-set \
--template-body file://template.yml \
--endpoint-url $AWS_ENDPOINT_URL
# List change sets
aws cloudformation list-change-sets \
--stack-name my-stack \
--endpoint-url $AWS_ENDPOINT_URL
# Describe a change set
aws cloudformation describe-change-set \
--stack-name my-stack \
--change-set-name my-change-set \
--endpoint-url $AWS_ENDPOINT_URL
# Delete a change set
aws cloudformation delete-change-set \
--stack-name my-stack \
--change-set-name my-change-set \
--endpoint-url $AWS_ENDPOINT_URL
Lambda + SQS Event Source Mapping
Deploy a Lambda function wired to an SQS queue as a single stack:
# template.yml
Resources:
MyQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: my-queue
MyFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-function
Runtime: nodejs22.x
Handler: index.handler
Role: arn:aws:iam::000000000000:role/lambda-role
Code:
ZipFile: |
exports.handler = async (event) => {
console.log(JSON.stringify(event));
};
MyESM:
Type: AWS::Lambda::EventSourceMapping
Properties:
FunctionName: !Ref MyFunction
EventSourceArn: !GetAtt MyQueue.Arn
Enabled: true
BatchSize: 10
aws cloudformation create-stack \
--stack-name my-lambda-sqs-stack \
--template-body file://template.yml \
--endpoint-url $AWS_ENDPOINT_URL
Dependency ordering
Use !Ref MyFunction (not a plain string) for FunctionName so CloudFormation
provisions the function before the event source mapping.