0
# Iterators and Dynamic Blocks
1
2
Iterator support for for_each constructs and dynamic block generation, enabling scalable and flexible infrastructure patterns.
3
4
## Capabilities
5
6
### TerraformIterator Class
7
8
Abstract base class providing iterator functionality for creating multiple similar resources or dynamic configuration blocks.
9
10
```typescript { .api }
11
/**
12
* Base iterator class for for_each and dynamic block constructs
13
*/
14
abstract class TerraformIterator {
15
/**
16
* Create an iterator from a list
17
* @param list - Array to iterate over
18
* @returns List iterator instance
19
*/
20
static fromList(list: any[]): ListTerraformIterator;
21
22
/**
23
* Create an iterator from a complex list with map conversion
24
* @param list - Complex list to iterate over
25
* @param mapKeyAttributeName - Attribute to use as map key
26
* @returns Dynamic list iterator instance
27
*/
28
static fromComplexList(
29
list: any[],
30
mapKeyAttributeName: string
31
): DynamicListTerraformIterator;
32
33
/**
34
* Create an iterator from a map/object
35
* @param map - Map to iterate over
36
* @returns Map iterator instance
37
*/
38
static fromMap(map: {[key: string]: any}): MapTerraformIterator;
39
40
/**
41
* Create an iterator from resources with for_each
42
* @param resource - Resource with for_each
43
* @returns Resource iterator instance
44
*/
45
static fromResources(resource: ITerraformResource): ResourceTerraformIterator;
46
47
/**
48
* Create an iterator from data sources with for_each
49
* @param resource - Data source with for_each
50
* @returns Resource iterator instance
51
*/
52
static fromDataSources(resource: ITerraformResource): ResourceTerraformIterator;
53
54
/**
55
* Get string attribute from current iteration
56
* @param attribute - Attribute name
57
* @returns String value
58
*/
59
getString(attribute: string): string;
60
61
/**
62
* Get number attribute from current iteration
63
* @param attribute - Attribute name
64
* @returns Number value
65
*/
66
getNumber(attribute: string): number;
67
68
/**
69
* Get boolean attribute from current iteration
70
* @param attribute - Attribute name
71
* @returns Boolean value
72
*/
73
getBoolean(attribute: string): IResolvable;
74
75
/**
76
* Get any attribute from current iteration
77
* @param attribute - Attribute name
78
* @returns Any value
79
*/
80
getAny(attribute: string): IResolvable;
81
82
/**
83
* Get list attribute from current iteration
84
* @param attribute - Attribute name
85
* @returns String array
86
*/
87
getList(attribute: string): string[];
88
89
/**
90
* Get number list attribute from current iteration
91
* @param attribute - Attribute name
92
* @returns Number array
93
*/
94
getNumberList(attribute: string): number[];
95
96
/**
97
* Get map attribute from current iteration
98
* @param attribute - Attribute name
99
* @returns Map of any values
100
*/
101
getMap(attribute: string): {[key: string]: any};
102
103
/**
104
* Get string map attribute from current iteration
105
* @param attribute - Attribute name
106
* @returns Map of string values
107
*/
108
getStringMap(attribute: string): {[key: string]: string};
109
110
/**
111
* Get number map attribute from current iteration
112
* @param attribute - Attribute name
113
* @returns Map of number values
114
*/
115
getNumberMap(attribute: string): {[key: string]: number};
116
117
/**
118
* Get boolean map attribute from current iteration
119
* @param attribute - Attribute name
120
* @returns Map of boolean values
121
*/
122
getBooleanMap(attribute: string): {[key: string]: boolean};
123
124
/**
125
* Get any map attribute from current iteration
126
* @param attribute - Attribute name
127
* @returns Map of any values
128
*/
129
getAnyMap(attribute: string): {[key: string]: any};
130
131
/**
132
* Create dynamic block content
133
* @param attributes - Attributes for the dynamic block
134
* @returns Dynamic block content
135
*/
136
dynamic(attributes: {[key: string]: any}): IResolvable;
137
138
/**
139
* Get keys from the iterator
140
* @returns Iterator keys
141
*/
142
keys(): IResolvable;
143
144
/**
145
* Get values from the iterator
146
* @returns Iterator values
147
*/
148
values(): IResolvable;
149
150
/**
151
* Pluck a specific property from each item
152
* @param property - Property name to extract
153
* @returns List of property values
154
*/
155
pluckProperty(property: string): IResolvable;
156
157
/**
158
* Create a for expression over the iterator for lists
159
* @param expression - Expression to evaluate for each item
160
* @returns For expression result
161
*/
162
forExpressionForList(expression: string | IResolvable): IResolvable;
163
164
/**
165
* Create a for expression over the iterator for maps
166
* @param keyExpression - Expression for map keys
167
* @param valueExpression - Expression for map values
168
* @returns For expression result
169
*/
170
forExpressionForMap(
171
keyExpression: string | IResolvable,
172
valueExpression: string | IResolvable
173
): IResolvable;
174
}
175
```
176
177
### Iterator Implementations
178
179
#### ListTerraformIterator
180
181
Iterator for arrays and lists.
182
183
```typescript { .api }
184
/**
185
* Iterator for lists and arrays
186
*/
187
class ListTerraformIterator extends TerraformIterator {
188
constructor(list: any[]);
189
190
readonly list: any[];
191
}
192
```
193
194
**Usage Examples:**
195
196
```typescript
197
import { TerraformIterator, AwsInstance } from "cdktf";
198
199
// Create instances for multiple environments
200
const environments = ["dev", "staging", "prod"];
201
const envIterator = TerraformIterator.fromList(environments);
202
203
new AwsInstance(this, "web-servers", {
204
forEach: envIterator,
205
ami: "ami-12345678",
206
instanceType: "t2.micro",
207
tags: {
208
Environment: envIterator.getString("each.value"),
209
Name: `web-${envIterator.getString("each.value")}`
210
}
211
});
212
213
// Using with complex objects
214
const serverConfigs = [
215
{ name: "web", type: "t2.micro", count: 2 },
216
{ name: "db", type: "t3.large", count: 1 },
217
{ name: "cache", type: "t3.medium", count: 1 }
218
];
219
220
const configIterator = TerraformIterator.fromList(serverConfigs);
221
222
new AwsInstance(this, "servers", {
223
forEach: configIterator,
224
ami: "ami-12345678",
225
instanceType: configIterator.getString("each.value.type"),
226
tags: {
227
Name: configIterator.getString("each.value.name"),
228
Type: configIterator.getString("each.value.name")
229
}
230
});
231
```
232
233
#### MapTerraformIterator
234
235
Iterator for maps and objects.
236
237
```typescript { .api }
238
/**
239
* Iterator for maps and objects
240
*/
241
class MapTerraformIterator extends TerraformIterator {
242
constructor(map: {[key: string]: any});
243
244
readonly map: {[key: string]: any};
245
}
246
```
247
248
**Usage Examples:**
249
250
```typescript
251
import { TerraformIterator, AwsS3Bucket } from "cdktf";
252
253
// Create buckets for different purposes
254
const buckets = {
255
"logs": { versioning: true, encryption: true },
256
"assets": { versioning: false, encryption: false },
257
"backups": { versioning: true, encryption: true }
258
};
259
260
const bucketIterator = TerraformIterator.fromMap(buckets);
261
262
new AwsS3Bucket(this, "buckets", {
263
forEach: bucketIterator,
264
bucket: `my-app-${bucketIterator.getString("each.key")}`,
265
versioning: [{
266
enabled: bucketIterator.getBoolean("each.value.versioning")
267
}],
268
serverSideEncryptionConfiguration: bucketIterator.getBoolean("each.value.encryption") ? [
269
{
270
rule: [{
271
applyServerSideEncryptionByDefault: [{
272
sseAlgorithm: "AES256"
273
}]
274
}]
275
}
276
] : []
277
});
278
```
279
280
#### ResourceTerraformIterator
281
282
Iterator for resources created with for_each.
283
284
```typescript { .api }
285
/**
286
* Iterator for resources with for_each
287
*/
288
class ResourceTerraformIterator extends TerraformIterator {
289
constructor(resource: ITerraformResource);
290
291
readonly resource: ITerraformResource;
292
}
293
```
294
295
### Dynamic Blocks
296
297
Dynamic blocks allow you to generate multiple nested blocks based on iteration.
298
299
**Usage Examples:**
300
301
```typescript
302
import { TerraformIterator } from "cdktf";
303
304
// Dynamic security group rules
305
const ingressRules = [
306
{ from_port: 80, to_port: 80, protocol: "tcp", cidr_blocks: ["0.0.0.0/0"] },
307
{ from_port: 443, to_port: 443, protocol: "tcp", cidr_blocks: ["0.0.0.0/0"] },
308
{ from_port: 22, to_port: 22, protocol: "tcp", cidr_blocks: ["10.0.0.0/8"] }
309
];
310
311
const ruleIterator = TerraformIterator.fromList(ingressRules);
312
313
new AwsSecurityGroup(this, "web-sg", {
314
namePrefix: "web-",
315
vpcId: vpc.id,
316
317
// Dynamic ingress blocks
318
dynamic: {
319
ingress: ruleIterator.dynamic({
320
fromPort: ruleIterator.getNumber("each.value.from_port"),
321
toPort: ruleIterator.getNumber("each.value.to_port"),
322
protocol: ruleIterator.getString("each.value.protocol"),
323
cidrBlocks: ruleIterator.getList("each.value.cidr_blocks")
324
})
325
}
326
});
327
328
// Dynamic tags based on map
329
const tags = {
330
Environment: "production",
331
Team: "platform",
332
Project: "web-app"
333
};
334
335
const tagIterator = TerraformIterator.fromMap(tags);
336
337
new AwsInstance(this, "web", {
338
ami: "ami-12345678",
339
instanceType: "t2.micro",
340
341
// Dynamic tags
342
dynamic: {
343
tag: tagIterator.dynamic({
344
key: tagIterator.getString("each.key"),
345
value: tagIterator.getString("each.value"),
346
propagateAtLaunch: true
347
})
348
}
349
});
350
```
351
352
### Advanced Iterator Patterns
353
354
#### Transforming Data with For Expressions
355
356
```typescript
357
import { TerraformIterator, Fn } from "cdktf";
358
359
const users = [
360
{ name: "alice", role: "admin", active: true },
361
{ name: "bob", role: "user", active: true },
362
{ name: "charlie", role: "user", active: false }
363
];
364
365
const userIterator = TerraformIterator.fromList(users);
366
367
// Get list of active user names
368
const activeUsers = userIterator.forExpressionForList(
369
Fn.conditional(
370
userIterator.getBoolean("each.value.active"),
371
userIterator.getString("each.value.name"),
372
null
373
)
374
);
375
376
// Create map of user roles
377
const userRoleMap = userIterator.forExpressionForMap(
378
userIterator.getString("each.value.name"),
379
userIterator.getString("each.value.role")
380
);
381
382
// Use in outputs
383
new TerraformOutput(this, "active_users", {
384
value: activeUsers,
385
description: "List of active users"
386
});
387
388
new TerraformOutput(this, "user_roles", {
389
value: userRoleMap,
390
description: "Map of users to their roles"
391
});
392
```
393
394
#### Nested Iterations
395
396
```typescript
397
import { TerraformIterator } from "cdktf";
398
399
// Create subnets for multiple AZs and tiers
400
const azs = ["us-east-1a", "us-east-1b", "us-east-1c"];
401
const tiers = ["public", "private"];
402
403
const azIterator = TerraformIterator.fromList(azs);
404
const tierIterator = TerraformIterator.fromList(tiers);
405
406
// Flatten to create all combinations
407
const subnetConfigs = azIterator.forExpressionForList(
408
tierIterator.forExpressionForList({
409
az: azIterator.getString("each.value"),
410
tier: tierIterator.getString("each.value"),
411
cidr: `10.0.${azIterator.getNumber("each.key")}.${tierIterator.getNumber("each.key") * 16}/20`
412
})
413
);
414
415
const subnetIterator = TerraformIterator.fromList(subnetConfigs);
416
417
new AwsSubnet(this, "subnets", {
418
forEach: subnetIterator,
419
vpcId: vpc.id,
420
availabilityZone: subnetIterator.getString("each.value.az"),
421
cidrBlock: subnetIterator.getString("each.value.cidr"),
422
mapPublicIpOnLaunch: subnetIterator.getString("each.value.tier") === "public",
423
tags: {
424
Name: `${subnetIterator.getString("each.value.tier")}-${subnetIterator.getString("each.value.az")}`,
425
Tier: subnetIterator.getString("each.value.tier"),
426
AZ: subnetIterator.getString("each.value.az")
427
}
428
});
429
```
430
431
## Type Definitions
432
433
```typescript { .api }
434
/**
435
* Interface for resources that can be iterated over
436
*/
437
interface ITerraformResource extends ITerraformDependable, ITerraformAddressable {
438
readonly terraformResourceType: string;
439
readonly fqn: string;
440
}
441
442
/**
443
* Dynamic block configuration
444
*/
445
interface DynamicBlockConfig {
446
/**
447
* Iterator to use for the dynamic block
448
*/
449
readonly forEach: ITerraformIterator;
450
451
/**
452
* Content to generate for each iteration
453
*/
454
readonly content: {[key: string]: any};
455
456
/**
457
* Iterator variable name (defaults to each)
458
*/
459
readonly iterator?: string;
460
}
461
```