CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-cdktf

Cloud Development Kit for Terraform - programmatic infrastructure as code using familiar programming languages

Overview
Eval results
Files

iterators-dynamic.mddocs/

Iterators and Dynamic Blocks

Iterator support for for_each constructs and dynamic block generation, enabling scalable and flexible infrastructure patterns.

Capabilities

TerraformIterator Class

Abstract base class providing iterator functionality for creating multiple similar resources or dynamic configuration blocks.

/**
 * Base iterator class for for_each and dynamic block constructs
 */
abstract class TerraformIterator {
  /**
   * Create an iterator from a list
   * @param list - Array to iterate over
   * @returns List iterator instance
   */
  static fromList(list: any[]): ListTerraformIterator;

  /**
   * Create an iterator from a complex list with map conversion
   * @param list - Complex list to iterate over
   * @param mapKeyAttributeName - Attribute to use as map key
   * @returns Dynamic list iterator instance
   */
  static fromComplexList(
    list: any[],
    mapKeyAttributeName: string
  ): DynamicListTerraformIterator;

  /**
   * Create an iterator from a map/object
   * @param map - Map to iterate over
   * @returns Map iterator instance
   */
  static fromMap(map: {[key: string]: any}): MapTerraformIterator;

  /**
   * Create an iterator from resources with for_each
   * @param resource - Resource with for_each
   * @returns Resource iterator instance
   */
  static fromResources(resource: ITerraformResource): ResourceTerraformIterator;

  /**
   * Create an iterator from data sources with for_each
   * @param resource - Data source with for_each
   * @returns Resource iterator instance
   */
  static fromDataSources(resource: ITerraformResource): ResourceTerraformIterator;

  /**
   * Get string attribute from current iteration
   * @param attribute - Attribute name
   * @returns String value
   */
  getString(attribute: string): string;

  /**
   * Get number attribute from current iteration
   * @param attribute - Attribute name
   * @returns Number value
   */
  getNumber(attribute: string): number;

  /**
   * Get boolean attribute from current iteration
   * @param attribute - Attribute name
   * @returns Boolean value
   */
  getBoolean(attribute: string): IResolvable;

  /**
   * Get any attribute from current iteration
   * @param attribute - Attribute name
   * @returns Any value
   */
  getAny(attribute: string): IResolvable;

  /**
   * Get list attribute from current iteration
   * @param attribute - Attribute name
   * @returns String array
   */
  getList(attribute: string): string[];

  /**
   * Get number list attribute from current iteration
   * @param attribute - Attribute name
   * @returns Number array
   */
  getNumberList(attribute: string): number[];

  /**
   * Get map attribute from current iteration
   * @param attribute - Attribute name
   * @returns Map of any values
   */
  getMap(attribute: string): {[key: string]: any};

  /**
   * Get string map attribute from current iteration
   * @param attribute - Attribute name
   * @returns Map of string values
   */
  getStringMap(attribute: string): {[key: string]: string};

  /**
   * Get number map attribute from current iteration
   * @param attribute - Attribute name
   * @returns Map of number values
   */
  getNumberMap(attribute: string): {[key: string]: number};

  /**
   * Get boolean map attribute from current iteration
   * @param attribute - Attribute name
   * @returns Map of boolean values
   */
  getBooleanMap(attribute: string): {[key: string]: boolean};

  /**
   * Get any map attribute from current iteration
   * @param attribute - Attribute name
   * @returns Map of any values
   */
  getAnyMap(attribute: string): {[key: string]: any};

  /**
   * Create dynamic block content
   * @param attributes - Attributes for the dynamic block
   * @returns Dynamic block content
   */
  dynamic(attributes: {[key: string]: any}): IResolvable;

  /**
   * Get keys from the iterator
   * @returns Iterator keys
   */
  keys(): IResolvable;

  /**
   * Get values from the iterator
   * @returns Iterator values
   */
  values(): IResolvable;

  /**
   * Pluck a specific property from each item
   * @param property - Property name to extract
   * @returns List of property values
   */
  pluckProperty(property: string): IResolvable;

  /**
   * Create a for expression over the iterator for lists
   * @param expression - Expression to evaluate for each item
   * @returns For expression result
   */
  forExpressionForList(expression: string | IResolvable): IResolvable;

  /**
   * Create a for expression over the iterator for maps
   * @param keyExpression - Expression for map keys
   * @param valueExpression - Expression for map values
   * @returns For expression result
   */
  forExpressionForMap(
    keyExpression: string | IResolvable,
    valueExpression: string | IResolvable
  ): IResolvable;
}

Iterator Implementations

ListTerraformIterator

Iterator for arrays and lists.

/**
 * Iterator for lists and arrays
 */
class ListTerraformIterator extends TerraformIterator {
  constructor(list: any[]);

  readonly list: any[];
}

Usage Examples:

import { TerraformIterator, AwsInstance } from "cdktf";

// Create instances for multiple environments
const environments = ["dev", "staging", "prod"];
const envIterator = TerraformIterator.fromList(environments);

new AwsInstance(this, "web-servers", {
  forEach: envIterator,
  ami: "ami-12345678",
  instanceType: "t2.micro",
  tags: {
    Environment: envIterator.getString("each.value"),
    Name: `web-${envIterator.getString("each.value")}`
  }
});

// Using with complex objects
const serverConfigs = [
  { name: "web", type: "t2.micro", count: 2 },
  { name: "db", type: "t3.large", count: 1 },
  { name: "cache", type: "t3.medium", count: 1 }
];

const configIterator = TerraformIterator.fromList(serverConfigs);

new AwsInstance(this, "servers", {
  forEach: configIterator,
  ami: "ami-12345678",
  instanceType: configIterator.getString("each.value.type"),
  tags: {
    Name: configIterator.getString("each.value.name"),
    Type: configIterator.getString("each.value.name")
  }
});

MapTerraformIterator

Iterator for maps and objects.

/**
 * Iterator for maps and objects
 */
class MapTerraformIterator extends TerraformIterator {
  constructor(map: {[key: string]: any});

  readonly map: {[key: string]: any};
}

Usage Examples:

import { TerraformIterator, AwsS3Bucket } from "cdktf";

// Create buckets for different purposes
const buckets = {
  "logs": { versioning: true, encryption: true },
  "assets": { versioning: false, encryption: false },
  "backups": { versioning: true, encryption: true }
};

const bucketIterator = TerraformIterator.fromMap(buckets);

new AwsS3Bucket(this, "buckets", {
  forEach: bucketIterator,
  bucket: `my-app-${bucketIterator.getString("each.key")}`,
  versioning: [{
    enabled: bucketIterator.getBoolean("each.value.versioning")
  }],
  serverSideEncryptionConfiguration: bucketIterator.getBoolean("each.value.encryption") ? [
    {
      rule: [{
        applyServerSideEncryptionByDefault: [{
          sseAlgorithm: "AES256"
        }]
      }]
    }
  ] : []
});

ResourceTerraformIterator

Iterator for resources created with for_each.

/**
 * Iterator for resources with for_each
 */
class ResourceTerraformIterator extends TerraformIterator {
  constructor(resource: ITerraformResource);

  readonly resource: ITerraformResource;
}

Dynamic Blocks

Dynamic blocks allow you to generate multiple nested blocks based on iteration.

Usage Examples:

import { TerraformIterator } from "cdktf";

// Dynamic security group rules
const ingressRules = [
  { from_port: 80, to_port: 80, protocol: "tcp", cidr_blocks: ["0.0.0.0/0"] },
  { from_port: 443, to_port: 443, protocol: "tcp", cidr_blocks: ["0.0.0.0/0"] },
  { from_port: 22, to_port: 22, protocol: "tcp", cidr_blocks: ["10.0.0.0/8"] }
];

const ruleIterator = TerraformIterator.fromList(ingressRules);

new AwsSecurityGroup(this, "web-sg", {
  namePrefix: "web-",
  vpcId: vpc.id,

  // Dynamic ingress blocks
  dynamic: {
    ingress: ruleIterator.dynamic({
      fromPort: ruleIterator.getNumber("each.value.from_port"),
      toPort: ruleIterator.getNumber("each.value.to_port"),
      protocol: ruleIterator.getString("each.value.protocol"),
      cidrBlocks: ruleIterator.getList("each.value.cidr_blocks")
    })
  }
});

// Dynamic tags based on map
const tags = {
  Environment: "production",
  Team: "platform",
  Project: "web-app"
};

const tagIterator = TerraformIterator.fromMap(tags);

new AwsInstance(this, "web", {
  ami: "ami-12345678",
  instanceType: "t2.micro",

  // Dynamic tags
  dynamic: {
    tag: tagIterator.dynamic({
      key: tagIterator.getString("each.key"),
      value: tagIterator.getString("each.value"),
      propagateAtLaunch: true
    })
  }
});

Advanced Iterator Patterns

Transforming Data with For Expressions

import { TerraformIterator, Fn } from "cdktf";

const users = [
  { name: "alice", role: "admin", active: true },
  { name: "bob", role: "user", active: true },
  { name: "charlie", role: "user", active: false }
];

const userIterator = TerraformIterator.fromList(users);

// Get list of active user names
const activeUsers = userIterator.forExpressionForList(
  Fn.conditional(
    userIterator.getBoolean("each.value.active"),
    userIterator.getString("each.value.name"),
    null
  )
);

// Create map of user roles
const userRoleMap = userIterator.forExpressionForMap(
  userIterator.getString("each.value.name"),
  userIterator.getString("each.value.role")
);

// Use in outputs
new TerraformOutput(this, "active_users", {
  value: activeUsers,
  description: "List of active users"
});

new TerraformOutput(this, "user_roles", {
  value: userRoleMap,
  description: "Map of users to their roles"
});

Nested Iterations

import { TerraformIterator } from "cdktf";

// Create subnets for multiple AZs and tiers
const azs = ["us-east-1a", "us-east-1b", "us-east-1c"];
const tiers = ["public", "private"];

const azIterator = TerraformIterator.fromList(azs);
const tierIterator = TerraformIterator.fromList(tiers);

// Flatten to create all combinations
const subnetConfigs = azIterator.forExpressionForList(
  tierIterator.forExpressionForList({
    az: azIterator.getString("each.value"),
    tier: tierIterator.getString("each.value"),
    cidr: `10.0.${azIterator.getNumber("each.key")}.${tierIterator.getNumber("each.key") * 16}/20`
  })
);

const subnetIterator = TerraformIterator.fromList(subnetConfigs);

new AwsSubnet(this, "subnets", {
  forEach: subnetIterator,
  vpcId: vpc.id,
  availabilityZone: subnetIterator.getString("each.value.az"),
  cidrBlock: subnetIterator.getString("each.value.cidr"),
  mapPublicIpOnLaunch: subnetIterator.getString("each.value.tier") === "public",
  tags: {
    Name: `${subnetIterator.getString("each.value.tier")}-${subnetIterator.getString("each.value.az")}`,
    Tier: subnetIterator.getString("each.value.tier"),
    AZ: subnetIterator.getString("each.value.az")
  }
});

Type Definitions

/**
 * Interface for resources that can be iterated over
 */
interface ITerraformResource extends ITerraformDependable, ITerraformAddressable {
  readonly terraformResourceType: string;
  readonly fqn: string;
}

/**
 * Dynamic block configuration
 */
interface DynamicBlockConfig {
  /**
   * Iterator to use for the dynamic block
   */
  readonly forEach: ITerraformIterator;

  /**
   * Content to generate for each iteration
   */
  readonly content: {[key: string]: any};

  /**
   * Iterator variable name (defaults to each)
   */
  readonly iterator?: string;
}

Install with Tessl CLI

npx tessl i tessl/npm-cdktf

docs

annotations-aspects.md

backend-configuration.md

core-infrastructure.md

index.md

iterators-dynamic.md

providers-modules.md

provisioners.md

resources-data-sources.md

terraform-functions.md

testing.md

tokens-expressions.md

variables-outputs.md

tile.json