» Modules

A Terraform module is a single directory that contains one or more configuration files.

Modules let you reuse configurations across projects and teams, saving time, enforcing consistency, and reducing errors. For example, you could create a module to describe the configuration for all of your organization's public website buckets. When you package and share this module, other users can incorporate it into their configurations. As requirements evolve, you can make changes to your module once, release a new version, and apply those changes everywhere that module is used.

You can specify any existing public or private module in your cdktf.json file, and CDK for Terraform (CDKTF) generates the necessary code bindings for you to use in your application.

» Install Modules

You can use modules from the Terraform Registry and other sources like GitHub in your application. For example, the TypeScript project below has a main.ts file that defines AWS resources and uses the AWS VPC module.

import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { AwsProvider } from "@cdktf/provider-aws";
import { Vpc } from '.gen/modules/vpc';

class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new AwsProvider(this, "aws", {
      region: "us-east-1",
    });

    new Vpc(this, 'MyVpc', {
      name: 'my-vpc',
      cidr: '10.0.0.0/16',
      azs: ['us-west-2a', 'us-west-2b', 'us-west-2c'],
      privateSubnets: ['10.0.1.0/24', '10.0.2.0/24', '10.0.3.0/24'],
      publicSubnets: ['10.0.101.0/24', '10.0.102.0/24', '10.0.103.0/24'],
      enableNatGateway: true
    )
  }
}

const app = new App();
new MyStack(app, "hello-terraform");
app.synth();

» Add Module to cdktf.json

To use a module in your application, you must first add it to the terraformModules array in the cdktf.json configuration file.

To add a module from the Terraform Registry or a private registry, provide a fully qualified name: registry-namespace/module-name.

{
  "language": "typescript",
  "app": "npm run --silent compile && node main.js",
  "terraformProviders": [],
  "terraformModules": [
    {
      "name": "vpc",
      "source": "terraform-aws-modules/vpc/aws",
      "version": "~> 3.0"
    }
  ]
}

For local modules, use the object format.

{
  "language": "typescript",
  "app": "npm run --silent compile && node main.js",
  "terraformProviders": [],
  "terraformModules": [
    {
      "name": "my-local-module",
      "source": "./path/to/local/terraform/module"
    }
  ]
}

» Generate Module Bindings

Go to the working directory and run cdktf get. CDKTF automatically creates the appropriate module bindings in the ./.gen directory for you to use in your application.

» Work with Module Outputs

Modules often return data that you can use as inputs to other modules or resources. When this data is only available after Terraform applies the configuration, you must use Terraform Outputs.

» Examples

The TypeScript example below uses a local module and references its output as a Terraform output.

import { Construct } from "constructs";
import { App, TerraformStack, TerraformOutput } from "cdktf";
// This module can come from a registry or through a local / remote reference
import MyLocalModule from "./.gen/modules/my-local-module";

class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const localModule = new MyLocalModule(this, "local-module", {
      ipAddress: "127.0.0.1",
    });

    new TerraformOutput(this, "dns-server", {
      value: localModule.dnsServerOutput,
    });
  }
}

The Python example below uses a local module and references its output as a Terraform output.

#!/usr/bin/env python

from constructs import Construct
from cdktf import App, TerraformStack, TerraformOutput
# This module can come from a registry or through a local / remote reference
from imports.my_local_module import MyLocalModule


class MyStack(TerraformStack):
    def __init__(self, scope: Construct, ns: str):
        super().__init__(scope, ns)

        localModule = MyLocalModule(self, "local-module", ip_address='127.0.0.1')
        TerraformOutput(self, "dns-server", value=localModule.dns_server_output)

» Create Modules

While we generally recommend generating code bindings for modules, you can also use the TerraformHclModule class to reference any module that Terraform supports. Both methods create identical synthesized Terraform configuration files, but using TerraformHclModule does not generate any types or type-safe inputs or outputs.

The TypeScript example below uses TerraformHclModule to import an AWS module.

const provider = new AwsProvider(stack, "provider", {
  region: "us-east-1",
});

const module = new TerraformHclModule(stack, "Vpc", {
  source: "terraform-aws-modules/vpc/aws",
  // variables takes any input - please consult the docs of the module
  // to ensure the arguments are correct
  variables: {
    name: "my-vpc",
    cidr: "10.0.0.0/16",
    azs: ["us-west-2a", "us-west-2b", "us-west-2c"],
    privateSubnets: ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"],
    publicSubnets: ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"],
    enableNatGateway: true,
  },
  providers: [provider],
});