> ## Documentation Index
> Fetch the complete documentation index at: https://cdktn.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Variables and Outputs - CDK Terrain

> Input variables, local values, and output values allow you to request and publish named values.

Terraform can understand configurations written in either HashiCorp Configuration Language (HCL) syntax or JSON. Because neither of these is a programming language, Terraform has developed ways to enable users to request and publish named values. These are:

* [**Input Variables:**](#input-variables) These are like function arguments.
* [**Local Values**](#local-values): These are like a function's temporary local variables.
* [**Output Values**](#output-values): These are like function return values.

You may need to occasionally use these elements in your CDK Terrain (CDKTN) application instead of passing data through the conventions available in your preferred programming language.

## Input Variables

You can define [Terraform variables](https://developer.hashicorp.com/terraform/language/values/variables) as input parameters to customize [stacks](/concepts/stacks) and [modules](/concepts/modules). For example, rather than hardcoding the number and type of AWS EC2 instances to provision, you can define a variable that lets users change these parameters based on their needs.

### When to use Input Variables

Variables are useful when you plan to synthesize your CDKTN application into a JSON configuration file for Terraform. For example, when you are planning to store configurations and run Terraform inside [HCP Terraform](https://cloud.hashicorp.com/products/terraform).

If you plan to use CDKTN to manage your infrastructure, we recommend using your language's APIs to consume the data you would normally pass through Terraform variables. You can read from disk (synchronously) or from the environment variables, just as you would in any normal program.

<Warning>The synthesized Terraform configuration will contain any values that you pass directly to CDKTN constructs. This includes credentials and any other sensitive data provided as input for the `cdktn` application. If you plan to commit the generated `cdk.tf.json` to version control, use [input variables](/concepts/variables-and-outputs#input-variables) for secrets instead.</Warning>

### Define Input Variables

You must specify values in exactly the same way as you would in an HCL configuration file. Refer to the [Terraform variables documentation](https://developer.hashicorp.com/terraform/language/values/variables#variables-on-the-command-line) for details. The CDKTN CLI currently also supports configuration via [environment variables](https://developer.hashicorp.com/terraform/language/values/variables#environment-variables).

The following example uses `TerraformVariable` to provide inputs to resources.

<CodeGroup>
  ```ts TypeScript theme={null}
  const imageId = new TerraformVariable(this, "imageId", {
    type: "string",
    default: "ami-abcde123",
    description: "What AMI to use to create an instance",
  });
  new Instance(this, "hello", {
    ami: imageId.value,
    instanceType: "t2.micro",
  });
  ```

  ```java Java theme={null}
          TerraformVariable imageId = new TerraformVariable(this, "imageId", TerraformVariableConfig.builder()
                  .type("string")
                  .defaultValue("ami-abcde123")
                  .description("What AMI to use to create an instance")
                  .build()
          );

          new Instance(this, "hello", InstanceConfig.builder()
                  .ami(imageId.getStringValue())
                  .instanceType("t2.micro")
                  .build()
          );
  ```

  ```python Python theme={null}
  imageId = TerraformVariable(self, "imageId",
      type = "string",
      default = "ami-abcde123",
      description = "What AMI to use to create an instance"
  )
  Instance(self, "hello",
      ami = imageId.string_value,
      instance_type = "t2.micro"
  )
  ```

  ```csharp C# theme={null}
              TerraformVariable imageId = new TerraformVariable(this, "imageId", new TerraformVariableConfig
              {
                  Type = "string",
                  Default = "ami-abcde123",
                  Description = "What AMI to use to create an instance",
              });

              new Instance(this, "hello", new InstanceConfig
              {
                  Ami = imageId.StringValue,
                  InstanceType = "t2.micro",
              });
  ```

  ```go Go theme={null}
  imageId := cdktn.NewTerraformVariable(stack, jsii.String("imageId"), &cdktn.TerraformVariableConfig{
  	Type:        jsii.String("string"),
  	Default:     jsii.String("ami-abcde123"),
  	Description: jsii.String("What AMI to use to create an instance"),
  })
  instance.NewInstance(stack, jsii.String("hello"), &instance.InstanceConfig{
  	Ami:          imageId.StringValue(),
  	InstanceType: jsii.String("t2.micro"),
  })
  ```
</CodeGroup>

### Define Complex Input Variables

<CodeGroup>
  ```typescript TypeScript theme={null}
  const nodeGroupConfig = new TerraformVariable(this, "node-group-config", {
    type: VariableType.object({
      node_group_name: VariableType.STRING,
      instance_types: VariableType.list(VariableType.STRING),
      min_size: VariableType.NUMBER,
      desired_size: VariableType.NUMBER,
      max_size: VariableType.NUMBER,
    }),
    nullable: false,
    description: "Node group configuration",
  });

  new TerraformResource(this, "resource", {
    nodeGroupConfig: nodeGroupConfig.value,
  });
  ```

  ```go Go theme={null}
  nodeGroupConfig := cdktn.NewTerraformVariable(stack, jsii.String("node-group-config"), &cdktn.TerraformVariableConfig{
  	Type: cdktn.VariableType_Object(&map[string]*string{
  		"node_group_name": cdktn.VariableType_STRING(),
  		"instance_types":  cdktn.VariableType_List(cdktn.VariableType_STRING()),
  		"min_size":        cdktn.VariableType_NUMBER(),
  		"desired_size":    cdktn.VariableType_NUMBER(),
  		"max_size":        cdktn.VariableType_NUMBER(),
  	}),
  	Nullable:    jsii.Bool(false),
  	Description: jsii.String("Node group configuration"),
  })

  eksnodegroup.NewEksNodeGroup(stack, jsii.String("node-group"), &eksnodegroup.EksNodeGroupConfig{
  	ClusterName:   jsii.String("my-cluster"),
  	NodeRoleArn:   jsii.String("arn:::::dummy"),
  	SubnetIds:     jsii.Strings("id-1234"),
  	NodeGroupName: jsii.String(fmt.Sprintf("${%s.node_group_name}", *nodeGroupConfig.Fqn())),
  	InstanceTypes: cdktn.Token_AsList(fmt.Sprintf("${%s.instance_types}", *nodeGroupConfig.Fqn()), &cdktn.EncodingOptions{}),
  	ScalingConfig: &eksnodegroup.EksNodeGroupScalingConfig{
  		DesiredSize: cdktn.Token_AsNumber(fmt.Sprintf("${%s.desired_size}", *nodeGroupConfig.Fqn())),
  		MinSize:     cdktn.Token_AsNumber(fmt.Sprintf("${%s.min_size}", *nodeGroupConfig.Fqn())),
  		MaxSize:     cdktn.Token_AsNumber(fmt.Sprintf("${%s.max_size}", *nodeGroupConfig.Fqn())),
  	},
  })
  ```
</CodeGroup>

### Passing Input Variables to CDKTN

You can pass input variables to `cdktn diff`, `cdktn deploy`, and `cdktn destroy` in the following ways:

* Environment variable: `TF_VAR_imageId=ami-abcde123`
* `--var` CLI option: `cdktn deploy --var='imageId=ami-abcde123'`
* `--var-file` CLI option: `cdktn deploy --var-file=/path/to/variables.tfvars`
* Auto-loaded configuration files: We auto-load `*.auto.tfvars` and `terraform.tfvars` files found in the current working directory. Refer to the [Terraform documentation](https://developer.hashicorp.com/terraform/language/values/variables#variable-definitions-tfvars-files) for details.

## Local Values

A [Terraform local](https://developer.hashicorp.com/terraform/language/values/locals) assigns a name to an expression to allow repeated usage. They are similar to a local variables in a programming language.

### When to Use Local Values

Use local values when you need use [Terraform functions](/concepts/functions) to transform data that is only available when Terraform (or OpenTofu) applies a configuration. For example, instance IDs that cloud providers assign upon creation.

When values are available before [synthesizing your code](/cli-reference/commands#synth), we recommend using native programming language features to modify values instead.

### Define Local Values

The following example uses `TerraformLocal` to create a local value.

<CodeGroup>
  ```ts TypeScript theme={null}
  const commonTags = new TerraformLocal(this, "common_tags", {
    Service: "service_name",
    Owner: "owner",
  });

  new Instance(this, "example", {
    ami: "ami-abcde123",
    instanceType: "t2.micro",
    tags: commonTags.expression,
  });
  ```

  ```java Java theme={null}
          TerraformLocal commonTags = new TerraformLocal(this, "common_tags", new HashMap<String, String>(){{
              put("service", "service_name");
              put("owner", "owner");
          }});

          new Instance(this, "example", InstanceConfig.builder()
                  .tags((Map<String, String>) commonTags.getExpression())
                  .build()
          );
  ```

  ```python Python theme={null}
          commonTags = TerraformLocal(self, "common_tags", {
              "service": "service_name",
              "owner": "owner"
          })

          Instance(self, "example",
              tags = commonTags.as_string_map
          )
  ```

  ```csharp C# theme={null}
  TerraformLocal commonTags = new TerraformLocal(this, "common_tags", new Dictionary<string, string> {
      { "Service", "service_name" },
      { "Owner", "owner" },
  });
  new Instance(this, "example", new InstanceConfig
  {
      Ami = "ami-abcde123",
      InstanceType = "t2.micro",
      Tags = Token.AsStringMap(commonTags.Expression),
  });
  ```

  ```go Go theme={null}
  commonTags := cdktn.NewTerraformLocal(stack, jsii.String("common_tags"), map[string]string{
  	"Service": "service_name",
  	"Owner":   "owner",
  })
  instance.NewInstance(stack, jsii.String("example"), &instance.InstanceConfig{
  	Ami:          jsii.String("ami-abcde123"),
  	InstanceType: jsii.String("t2.micro"),
  	Tags:         commonTags.AsStringMap(),
  })
  ```
</CodeGroup>

When you run `cdktn synth` the `TerraformLocal` synthesizes to the following JSON.

```json theme={null}
"locals": {
    "common_tags": {
      "Service": "service_name",
      "Owner": "owner"
    }
}
...
"resource": {
  "aws_instance": {
    "example": {
      "tags": "${local.common_tags}"
    }
  }
}
```

## Output Values

You can define [Terraform outputs](https://developer.hashicorp.com/terraform/language/values/outputs) to export structured data about your resources. Terraform prints the output value for the user after it applies infrastructure changes, and you can use this information as a data source for other [Terraform workspaces](https://developer.hashicorp.com/terraform/language/state/workspaces).

### When to use Output Values

Use outputs to make data from [Terraform resources](/concepts/resources) and [data sources](/concepts/data-sources) available for further consumption or to share data between [stacks](/concepts/stacks). Outputs are particularly useful when you need to access data that is only known after Terraform applies the configuration. For example, you may want to get the URL of a newly provisioned server.

When values are available before [synthesizing your code](/cli-reference/commands#synth), we recommend using the functionality in your preferred programming language to supply this data as direct inputs.

The following example uses a `TerraformOutput` to create an output.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { TerraformLocal, TerraformStack, TerraformVariable } from "cdktn";
  import { Construct } from "constructs";
  import { App, TerraformOutput } from "cdktn";
  interface OutputVariableStackConfig {
    readonly myDomain: string;
  }

  class OutputVariableStack extends TerraformStack {
    constructor(
      scope: Construct,
      name: string,
      config: OutputVariableStackConfig,
    ) {
      super(scope, name);

      const { myDomain } = config;

      new TerraformOutput(this, "my-domain", {
        value: myDomain,
      });
    }
  }

  const app = new App();
  new OutputVariableStack(app, "cdktn-producer", {
    myDomain: "example.com",
  });
  app.synth();
  ```

  ```java Java theme={null}
  import software.constructs.Construct;
  import io.cdktn.cdktn.TerraformStack;
  import io.cdktn.cdktn.App;
  import io.cdktn.cdktn.TerraformOutput;
  import io.cdktn.cdktn.TerraformOutputConfig;

  public class VariablesAndOutputsValues extends TerraformStack {

      public VariablesAndOutputsValues(Construct scope, String id, VariablesAndOutputsValuesProps props){
          super(scope, id);

          new TerraformOutput(this, "my-domain", TerraformOutputConfig.builder()
                  .value(props.myDomain)
                  .build()
          );
      }

      public static class VariablesAndOutputsValuesProps {
          public String myDomain;
          public VariablesAndOutputsValuesProps(String myDomain){
              this.myDomain = myDomain;
          }
      }

      public static void main(String[] args) {
          final App app = new App();
          new VariablesAndOutputsValues(app, "cdktn-producer", new VariablesAndOutputsValuesProps("example.com"));
          app.synth();
      }
  }
  ```

  ```python Python theme={null}
  from constructs import Construct
  from cdktn import App, TerraformStack, TerraformOutput

  class OutputValuesProps:
      myDomain: str
      def __init__(self, myDomain: str):
          self.myDomain = myDomain

  class OutputValuesStack(TerraformStack):
      def __init__(self, scope: Construct, name: str, props: OutputValuesProps):
          super().__init__(scope, name)

          TerraformOutput(self, "my-domain",
              value = props.myDomain
          )

  app = App()
  OutputValuesStack(app, "cdktn-producer", OutputValuesProps(myDomain = "example.com"))
  app.synth()
  ```

  ```csharp C# theme={null}
  using System;
  using System.IO;
  using System.Collections.Generic;
  using System.Linq;
  using Constructs;
  using Io.Cdktn;
  using aws.Provider;
  using aws.Instance;

  namespace Examples
  {
      class OutputVariableStackConfig
      {
          public OutputVariableStackConfig(string myDomain)
          {
              this.MyDomain = myDomain;
          }

          public string MyDomain { get; set; }
      }

      class OutputVariableStack : TerraformStack
      {
          public OutputVariableStack(Construct scope, string name, OutputVariableStackConfig config) : base(scope, name)
          {
              new TerraformOutput(this, "my-domain", new TerraformOutputConfig
              {
                  Value = config.MyDomain,
              });
          }
                  public static void Main(string[] args)
                  {
                      App app = new App();
                      new OutputVariableStack(app, "cdktn-producer", new OutputVariableStackConfig("example.com"));
                      app.Synth();
                  }
      }

  }
  ```

  ```go Go theme={null}

  import (
  	"github.com/aws/constructs-go/constructs/v10"
  	"github.com/aws/jsii-runtime-go"
  	"github.com/open-constructs/cdk-terrain-go/cdktn"
  )

  type OutputsStackConfig struct {
  	MyDomain string
  }

  func NewOutputsStack(scope constructs.Construct, name string, config OutputsStackConfig) cdktn.TerraformStack {
  	stack := cdktn.NewTerraformStack(scope, &name)

  	cdktn.NewTerraformOutput(stack, jsii.String("my-domain"), &cdktn.TerraformOutputConfig{
  		Value: &config.MyDomain,
  	})

  	return stack
  }

  func main() {
  	app := cdktn.NewApp(nil)

  	NewOutputsStack(app, "outputs", OutputsStackConfig{
  		MyDomain: "example.com",
  	})

  	app.Synth()
  }

  ```
</CodeGroup>

### Define Output Values

To access outputs, use the `_output` suffix for Python and the `Output` suffix for other languages.

Outputs return an HCL expression representing the underlying Terraform resource, so the return type must always be `string`. When `TerraformOutput` is any other type than string, you must add a typecast to compile the application (e.g. `mod.numberOutput as number`). If a module returns a list, you must use an escape hatch to access items or loop over it. Refer to the [Resources page](/concepts/resources) for more information about how to use escape hatches.

The following Typescript example uses `TerraformOutput` to create an output for a Random provider resource.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { TerraformLocal, TerraformStack, TerraformVariable } from "cdktn";
  import { Construct } from "constructs";
  import { App, TerraformOutput } from "cdktn";
  import { RandomProvider } from "@cdktn/provider-random/lib/provider";
  import { Pet } from "@cdktn/provider-random/lib/pet";
  class OutputsUsageStack extends TerraformStack {
    constructor(scope: Construct, name: string) {
      super(scope, name);

      new RandomProvider(this, "random", {});
      const pet = new Pet(this, "pet", {});

      new TerraformOutput(this, "random-pet", {
        value: pet.id,
      });
    }
  }

  const app = new App();
  new OutputsUsageStack(app, "outputs-usage");
  app.synth();
  ```

  ```java Java theme={null}
  import software.constructs.Construct;
  import io.cdktn.cdktn.TerraformStack;
  import io.cdktn.cdktn.App;
  import io.cdktn.cdktn.TerraformOutput;
  import io.cdktn.cdktn.TerraformOutputConfig;
  import imports.random.pet.Pet;
  import imports.random.provider.RandomProvider;

  public class VariablesAndOutputsDefineValues extends TerraformStack {

      public VariablesAndOutputsDefineValues(Construct scope, String id) {
          super(scope, id);

          new RandomProvider(this, "random");

          Pet pet = new Pet(this, "pet");

          new TerraformOutput(this, "random-pet", TerraformOutputConfig.builder()
                  .value(pet.getId())
                  .build());

      public static void main(String[] args) {
          final App app = new App();
          new VariablesAndOutputsDefineValues(app, "cdktn-demo");
          app.synth();
      }
  }
  ```

  ```python Python theme={null}
  from imports.random.provider import RandomProvider

  from constructs import Construct
  from cdktn import App, TerraformStack, TerraformOutput

  class DefineOutputStack(TerraformStack):
      def __init__(self, scope: Construct, name: str):
          super().__init__(scope, name)

          RandomProvider(self, "random")
          pet = random.pet.Pet(self, "pet")

          TerraformOutput(self, "random-pet",
              value = pet.id
          )

  app = App()
  DefineOutputStack(app, "cdktn-demo")
  app.synth()
  ```

  ```csharp C# theme={null}
  using System;
  using System.IO;
  using System.Collections.Generic;
  using System.Linq;
  using Constructs;
  using Io.Cdktn;
  using random.Provider;
  using random.Pet;

  namespace Examples
  {
      class OutputsUsageStack : TerraformStack
      {
          public OutputsUsageStack(Construct scope, string name) : base(scope, name)
          {
              new RandomProvider(this, "random", new RandomProviderConfig());
              var pet = new Pet(this, "pet", new PetConfig());
              new TerraformOutput(this, "random-pet", new TerraformOutputConfig
              {
                  Value = pet.Id,
              });
          }
                  public static void Main(string[] args)
                  {
                      App app = new App();
                      new OutputsUsageStack(app, "outputs-usage");
                      app.Synth();
                  }
      }

  }
  ```

  ```go Go theme={null}

  import (
  	"github.com/aws/constructs-go/constructs/v10"
  	"github.com/aws/jsii-runtime-go"
  	"github.com/open-constructs/cdk-terrain-go/cdktn"
  	"github.com/open-constructs/cdk-terrain/examples/go/documentation/generated/hashicorp/random/pet"
  	random "github.com/open-constructs/cdk-terrain/examples/go/documentation/generated/hashicorp/random/provider"
  )

  func NewOutputsUsageStack(scope constructs.Construct, name string) cdktn.TerraformStack {
  	stack := cdktn.NewTerraformStack(scope, &name)

  	random.NewRandomProvider(stack, jsii.String("random"), &random.RandomProviderConfig{})

  	pet := pet.NewPet(stack, jsii.String("pet"), &pet.PetConfig{})
  	cdktn.NewTerraformOutput(stack, jsii.String("random-pet"), &cdktn.TerraformOutputConfig{
  		Value: pet.Id(),
  	})

  	return stack
  }

  func main() {
  	app := cdktn.NewApp(nil)

  	NewOutputsUsageStack(app, "outputs-usage")

  	app.Synth()
  }

  ```
</CodeGroup>

When you run `cdktn synth`, CDKTN synthesizes the code to the following JSON configuration.

```json theme={null}
"output": {
  "random-pet": {
    "value": "${random_pet.pet.id}"
  }
}
```

When you run `cdktn deploy`, CDKTN displays the following output.

```
Deploying Stack: cdktn-demo
Resources
 ✔ RANDOM_PET           pet                 random_pet.pet

Summary: 1 created, 0 updated, 0 destroyed.

Output: random-pet = choice-haddock
```

### Define & Reference Outputs via Remote State

The following example uses outputs to share data between stacks, each of which has a [remote backend](/concepts/remote-backends) to store the Terraform state files remotely.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { TerraformLocal, TerraformStack, TerraformVariable } from "cdktn";
  import { Construct } from "constructs";
  import { App, TerraformOutput } from "cdktn";
  import {
    CloudBackend,
    DataTerraformRemoteState,
    NamedCloudWorkspace,
  } from "cdktn";

  class Producer extends TerraformStack {
    constructor(scope: Construct, name: string) {
      super(scope, name);

      new CloudBackend(this, {
        organization: "hashicorp",
        workspaces: new NamedCloudWorkspace("producer"),
      });

      new RandomProvider(this, "random", {});
      const pet = new Pet(this, "pet", {});

      new TerraformOutput(this, "random-pet", {
        value: pet.id,
      });
    }
  }

  class Consumer extends TerraformStack {
    constructor(scope: Construct, name: string) {
      super(scope, name);

      new CloudBackend(this, {
        organization: "hashicorp",
        workspaces: new NamedCloudWorkspace("consumer"),
      });

      const remoteState = new DataTerraformRemoteState(this, "remote-pet", {
        organization: "hashicorp",
        workspaces: {
          name: "producer",
        },
      });

      new TerraformOutput(this, "random-remote-pet", {
        value: remoteState.getString("random-pet"),
      });
    }
  }

  const app = new App();
  new Producer(app, "cdktn-producer");
  new Consumer(app, "cdktn-consumer");
  app.synth();
  ```

  ```java Java theme={null}
  import imports.random.provider.RandomProvider;
  import imports.random.pet.Pet;

  import software.constructs.Construct;
  import io.cdktn.cdktn.App;
  import io.cdktn.cdktn.TerraformStack;
  import io.cdktn.cdktn.TerraformOutput;
  import io.cdktn.cdktn.TerraformOutputConfig;
  import io.cdktn.cdktn.CloudBackend;
  import io.cdktn.cdktn.CloudBackendConfig;
  import io.cdktn.cdktn.NamedCloudWorkspace;
  import io.cdktn.cdktn.NamedRemoteWorkspace;
  import io.cdktn.cdktn.DataTerraformRemoteState;
  import io.cdktn.cdktn.DataTerraformRemoteStateRemoteConfig;

  public class VariablesAndOutputsRemoteState {

      public static class Producer extends TerraformStack{

          public Producer(Construct scope, String id){
              super(scope, id);

              new CloudBackend(this, CloudBackendConfig.builder()
                      .organization("hashicorp")
                      .workspaces(new NamedCloudWorkspace("producer"))
                      .build()
              );

              new RandomProvider(this, "random");
              Pet pet = new Pet(this, "pet");

              new TerraformOutput(this, "random-pet", TerraformOutputConfig.builder()
                      .value(pet.getId())
                      .build()
              );
          }
      }

      public static class Consumer extends TerraformStack{

          public Consumer(Construct scope, String id){
              super(scope, id);

              new CloudBackend(this, CloudBackendConfig.builder()
                      .organization("hashicorp")
                      .workspaces(new NamedCloudWorkspace("consumer"))
                      .build()
              );

              DataTerraformRemoteState remoteState = new DataTerraformRemoteState(this, "remote-pet", DataTerraformRemoteStateRemoteConfig.builder()
                      .organization("hashicorp")
                      .workspaces(new NamedRemoteWorkspace("producer"))
                      .build()
              );
          }
      }

      public static void main(String[] args) {
          final App app = new App();
          new Producer(app, "cdktn-producer");
          new Consumer(app, "cdktn-consumer");
          app.synth();
      }
  }
  ```

  ```python Python theme={null}
  import imports.random as random

  from constructs import Construct
  from cdktn import App, TerraformStack, TerraformOutput, CloudBackend, NamedRemoteWorkspace, DataTerraformRemoteState

  class Producer(TerraformStack):
      def __init__(self, scope: Construct, name: str):
          super().__init__(scope, name)

          CloudBackend(self,
              organization = "hashicorp",
              workspaces = NamedCloudWorkspace("producer")
          )

          random.provider.RandomProvider(self, "random")
          pet = random.pet.Pet(self, "pet")

          TerraformOutput(self, "random-pet",
              value = pet.id
          )

  class Consumer(TerraformStack):
      def __init__(self, scope: Construct, name: str):
          super().__init__(scope, name)

          CloudBackend(self,
              organization = "hashicorp",
              workspaces = NamedCloudWorkspace("consumer")
          )

          remoteState = DataTerraformRemoteState(self, "remote-pet",
              organization = "hashicorp",
              workspaces = NamedRemoteWorkspace(name = "producer")
          )

          TerraformOutput(self, "random-remote-pet",
              value = remoteState.get_string("random-pet")
          )

  app = App()
  Producer(app, "cdktn-producer")
  Consumer(app, "cdktn-consumer")
  app.synth()
  ```

  ```csharp C# theme={null}
  using System;
  using System.IO;
  using System.Collections.Generic;
  using System.Linq;
  using Constructs;
  using Io.Cdktn;
  using random.Provider;
  using random.Pet;

  namespace Examples
  {
      class Producer : TerraformStack
      {
          public Producer(Construct scope, string name) : base(scope, name)
          {
              new CloudBackend(this, new CloudBackendConfig
              {
                  Organization = "hashicorp",
                  Workspaces = new NamedCloudWorkspace("producer"),
              });

              new RandomProvider(this, "random", new RandomProviderConfig());
              var pet = new Pet(this, "pet", new PetConfig());

              new TerraformOutput(this, "random-pet", new TerraformOutputConfig
              {
                  Value = pet.Id,
              });
          }
      }

      class Consumer : TerraformStack
      {
          public Consumer(Construct scope, string name) : base(scope, name)
          {
              new CloudBackend(this, new CloudBackendConfig
              {
                  Organization = "hashicorp",
                  Workspaces = new NamedCloudWorkspace("consumer"),
              });

              DataTerraformRemoteState remoteState = new DataTerraformRemoteState(this, "remote-state", new DataTerraformRemoteStateRemoteConfig
              {
                  Organization = "hashicorp",
                  Workspaces = new NamedRemoteWorkspace("producer"),
              });

              new TerraformOutput(this, "random-remote-pet", new TerraformOutputConfig
              {
                  Value = remoteState.GetString("random-pet"),
              });
          }
      }

      class Main
      {
                  public static void Main(string[] args)
                  {
                      App app = new App();
                      new Producer(app, "cdktn-producer");
                      new Consumer(app, "cdktn-consumer");
                      app.Synth();
                  }
      }

  }
  ```

  ```go Go theme={null}

  import (
  	"github.com/aws/constructs-go/constructs/v10"
  	"github.com/aws/jsii-runtime-go"
  	"github.com/open-constructs/cdk-terrain-go/cdktn"
  	"github.com/open-constructs/cdk-terrain/examples/go/documentation/generated/hashicorp/random/pet"
  	random "github.com/open-constructs/cdk-terrain/examples/go/documentation/generated/hashicorp/random/provider"
  )

  func NewProducerStack(scope constructs.Construct, name string) cdktn.TerraformStack {
  	stack := cdktn.NewTerraformStack(scope, &name)

  	cdktn.NewCloudBackend(stack, &cdktn.CloudBackendConfig{
  		Organization: jsii.String("hashicorp"),
  		Workspaces:   cdktn.NewNamedCloudWorkspace(jsii.String("producer"), nil),
  	})

  	random.NewRandomProvider(stack, jsii.String("random"), &random.RandomProviderConfig{})

  	pet := pet.NewPet(stack, jsii.String("pet"), &pet.PetConfig{})
  	cdktn.NewTerraformOutput(stack, jsii.String("random-pet"), &cdktn.TerraformOutputConfig{
  		Value: pet.Id(),
  	})

  	return stack
  }

  func NewConsumerStack(scope constructs.Construct, name string) cdktn.TerraformStack {
  	stack := cdktn.NewTerraformStack(scope, &name)

  	cdktn.NewCloudBackend(stack, &cdktn.CloudBackendConfig{
  		Organization: jsii.String("hashicorp"),
  		Workspaces:   cdktn.NewNamedCloudWorkspace(jsii.String("consumer"), nil),
  	})

  	remoteState := cdktn.NewDataTerraformRemoteState(stack, jsii.String("remote-pet"), &cdktn.DataTerraformRemoteStateRemoteConfig{
  		Organization: jsii.String("hashicorp"),
  		Workspaces:   cdktn.NewNamedCloudWorkspace(jsii.String("producer"), nil),
  	})

  	cdktn.NewTerraformOutput(stack, jsii.String("random-remote-pet"), &cdktn.TerraformOutputConfig{
  		Value: remoteState.GetString(jsii.String("random-pet")),
  	})

  	return stack
  }

  func main() {
  	app := cdktn.NewApp(nil)

  	NewProducerStack(app, "cdktn-producer")
  	NewConsumerStack(app, "cdktn-consumer")

  	app.Synth()
  }

  ```
</CodeGroup>
