Fn::ForEach

Fn::ForEach and Other Language Extension Functions

Plain CloudFormation 24 has no loops: five similar resources are five copies. The AWS 24 ::LanguageExtensions transform adds Fn::ForEach, Fn::Length and Fn::ToJsonString, DefaultValue for Fn::FindInMap, and functions in places that normally need literals, such as Ref targets and DeletionPolicy. AWS expands the template before the engine runs it. The new functions have no short YAML tags. Fn::ForEach::Name takes an identifier, a collection and a fragment whose key contains ${Identifier}:

infra/genres.yaml: one Parameter Store shelf per BookNest genreYAML
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::LanguageExtensions
Parameters:
  Genres: {Type: CommaDelimitedList, Default: "Fiction,Technology,Cooking,Travel"}
Resources:
  Fn::ForEach::GenreShelves:
    - Genre
    - !Ref Genres
    - Shelf${Genre}:
        Type: AWS::SSM::Parameter
        Properties: {Type: String, Value: !Sub "Shelf for ${Genre}"}
Outputs:
  GenreCount: {Value: {Fn::Length: !Ref Genres}}
  GenreJson: {Value: {Fn::ToJsonString: {genres: !Ref Genres}}}
Deploying the loop and listing the expanded resourcesShell
aws cloudformation deploy --stack-name booknest-genres --template-file genres.yaml \
  --capabilities CAPABILITY_AUTO_EXPAND
aws cloudformation get-template --stack-name booknest-genres --template-stage Processed \
  --output text --query 'keys(TemplateBody.Resources)'
aws cloudformation describe-stacks --stack-name booknest-genres --output text \
  --query 'Stacks[0].Outputs[].[OutputKey,OutputValue]'
Output
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - booknest-genres
ShelfFiction   ShelfTechnology   ShelfCooking   ShelfTravel
GenreCount   4
GenreJson   {"genres":{"Ref":"Genres"}}

CAPABILITY_AUTO_EXPAND acknowledges that a transform rewrites the template, and the Processed stage shows the four resources the loop produced. LocalStack 4.13.1 63,725 has gaps here. Fn::ToJsonString returned the unresolved Ref, where AWS returns {"genres":["Fiction","Technology","Cooking","Travel"]}. A Fn::ForEach in Outputs failed with Invalid definition type. And Shelf&{Genre}, AWS's form that drops non-alphanumeric characters so that Science Fiction becomes ShelfScienceFiction, failed with Fn::ForEach: no placeholder in logical resource id, so this list leaves out BookNest's two-word genres. Macros and Extensions covers the transform in depth.