Guideline how to structure bigger Terraform CDK deployments?

I have experience with AWS CDK and there we use L2 Constructs to structure the code. For example if we want to deploy a network with all relevant ressources we would do it on a separate construct and then use the returned date for subsequent constructs or resource.

How is this handled with Terraform CDK? Do we have an example, recommendation how to outsource network creation and then use the outputs for subsequent deployments?

I think the Application Architecture section in our best practices docs is what you are looking for.

Thanks for the link. I try to adapt it but I think I miss something basic. Please find following example:

import { Construct } from "constructs";
import { App, TerraformStack, RemoteBackend } from "cdktf";
import { AwsProvider, ec2 } from "@cdktf/provider-aws";
import { DataAwsIamPolicyDocument, IamInstanceProfile, IamPolicy, IamRole, IamRolePolicyAttachment } from "@cdktf/provider-aws/lib/iam";

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

    new AwsProvider(this, "AWS", {
      region: "eu-west-1",

    // IAM Roles
    const AssumeIamRoleEc2 = new DataAwsIamPolicyDocument(this, "instance-assume-role-policy", { version: "2012-10-17", statement: [{ effect: "Allow", actions: ["sts:AssumeRole"], principals: [{ type: "Service", identifiers: [""] }] }] })

    const CcNodeIamRole = new IamRole(this, "cc-node-iam-role", { name: "cc-node-iam-role", assumeRolePolicy: AssumeIamRoleEc2.json })

    const AssumeIamRoleCc = new DataAwsIamPolicyDocument(this, "cc-callhome-policy-document", { version: "2012-10-17", statement: [{ sid: "AllowDelegationForCallhome", effect: "Allow", actions: ["sts:AssumeRole"], resources: ["arn:aws:iam::223544365242:role/callhome-delegation-role"] }] })

    const CcCallhomePolicy = new IamPolicy(this, "cc-callhome-policy", { description: "Policy which allows STS AssumeRole when attached to a user or role. Used for CC callhome", name: "cc-callhome-policy", policy: AssumeIamRoleCc.json })

    new IamRolePolicyAttachment(this, "cc-callhome-policy-attachment", { policyArn: CcCallhomePolicy.arn, role: })

    // # Assign CC IAM Role to Instance Profile for CC instance attachment
    new IamInstanceProfile(this, "cc-host-profile", { name: "cc-host-profile", role: })

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

    new IamCustomConstruct(this, "IamTest")
    new AwsProvider(this, "AWS", {
      region: "eu-west-1",

    new ec2.Instance(this, "compute", {
      subnetId: "",
      ami: "ami-089950bc622d39ed8",
      instanceType: "t2.micro",
      keyName: "Key_MBP",
      securityGroups: ["sg-id"],

const app = new App();
const stack = new MyStack(app, "aws_instance");

new RemoteBackend(stack, {
  hostname: "",
  organization: "org",
  workspaces: {
    name: "test",

How can I call the I IamCustomConstruct and get the Role id from IamInstanceProfile to attach it to my instance which I should create in the main MyStack? Can somebody please give me here an example?

Hi @fdervisi :wave:

You can expose the constructs you create to the outside world like done in this example.
You can also only expose a single attribute (if that makes more sense for your use-case / encapsulation), refer to this example for that.

@ansgarm great! This was the solution! I was not really clear how to use constructs without initiated a new stackā€¦