# Terraform/OpenTofu

## Overview

Terraform and OpenTofu artifacts let you define, plan, and provision infrastructure resources declaratively using standard Terraform or OpenTofu configurations, while leveraging Bluebricks' orchestration engine for consistent, auditable execution across collections.

By encapsulating your IaC module as an artifact, you can integrate infrastructure changes directly into environment pipelines, apply collection-specific inputs, and ensure controlled, versioned rollouts.

<table><thead><tr><th width="242.71875">Feature</th><th>Details</th></tr></thead><tbody><tr><td><strong>Dual-engine support</strong></td><td>Select HashiCorp Terraform CLI or OpenTofu CLI per artifact</td></tr><tr><td><strong>Automatic state backend</strong></td><td>Bluebricks hosts and locks state (no S3 buckets or DynamoDB tables required)</td></tr><tr><td><strong>Input auto-wiring</strong></td><td>All props and secrets are passed in <code>0_bbx_props.auto.tfvars</code> at runtime</td></tr><tr><td><strong>Plan review</strong></td><td>Plans show resource actions and "known after apply" outputs</td></tr><tr><td><strong>Outputs capture</strong></td><td><code>terraform output -json</code> is parsed into artifact outputs after apply</td></tr><tr><td><strong>Version pinning</strong></td><td>The <code>version</code> field locks the CLI binary (defaults: Terraform 1.5.7, OpenTofu 1.8.7). See <a href="#version-pinning">version pinning</a> for limits and examples</td></tr><tr><td><strong>State import</strong></td><td>Optionally import an existing <code>.tfstate</code> file into managed state</td></tr></tbody></table>

For a complete guide to how inputs and outputs work across all IaC tools, see [Inputs & Outputs](/docs/orchestration/packages/inputs-and-outputs.md).

## Required files and directory structure

A Terraform/OpenTofu artifact requires standard `.tf` files in the directory specified by `native.path`:

```
my-terraform-artifact/
├── bricks.json             # Artifact manifest
└── iac/                    # native.path points here
    ├── main.tf             # Resource definitions
    ├── variables.tf        # Input variable declarations
    ├── outputs.tf          # Output declarations
    └── versions.tf         # Provider and Terraform version constraints
```

The `native.path` field in `bricks.json` must point to the directory containing your `.tf` files. Subdirectories, modules, and additional files (e.g., `terraform.tfvars`, `.tfvars` files) are supported.

## bricks.json reference

<table><thead><tr><th width="148.72265625">Field</th><th width="121.96875">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>type</code></strong></td><td>Yes</td><td><code>"terraform"</code> or <code>"opentofu"</code> (alias <code>"tofu"</code>)</td></tr><tr><td><strong><code>path</code></strong></td><td>Yes</td><td>Directory containing <code>main.tf</code>, modules, etc.</td></tr><tr><td><strong><code>version</code></strong></td><td>No</td><td>Locks the CLI binary for deterministic output</td></tr><tr><td><strong><code>state</code></strong></td><td>No</td><td><code>"managed"</code> (default) = Bluebricks backend</td></tr><tr><td><strong><code>state_path</code></strong></td><td>No</td><td>Relative <code>.tfstate</code> file to import on first run</td></tr></tbody></table>

### Version pinning

Pin a specific CLI version with the `native.version` field in `bricks.json`. Supported ranges:

| Tool      | Min version | Max version | Default |
| --------- | ----------- | ----------- | ------- |
| Terraform | 1.0.0       | 1.5.7       | 1.5.7   |
| OpenTofu  | 1.0.0       | Latest      | 1.8.7   |

Terraform is capped at 1.5.7 because later versions use the BSL license. OpenTofu tracks the latest open-source release.

<details>

<summary>Terraform example</summary>

```json
{
  "native": {
    "type": "terraform",
    "path": "./src/terraform",
    "version": "1.5.7"
  }
}
```

</details>

<details>

<summary>OpenTofu example</summary>

```json
{
  "native": {
    "type": "opentofu",
    "path": "./src/terraform",
    "version": "1.9.0"
  }
}
```

</details>

Verify your version configuration with a dry run:

```bash
bricks run . --dry --props-file properties.json
```

## Terraform vs OpenTofu

| Feature              | Terraform               | OpenTofu              |
| -------------------- | ----------------------- | --------------------- |
| **License**          | BSL 1.5.8+ (restricted) | MPL 2.0 (open source) |
| **Latest supported** | 1.5.7                   | Latest                |
| **Syntax**           | Identical               | Identical             |
| **Provider support** | Full                    | Full                  |

Terraform 1.5.7 and earlier use the MPL 2.0 license. Versions 1.5.8+ switched to the Business Source License (BSL), so Bluebricks caps Terraform at 1.5.7. OpenTofu is always MPL 2.0 with no restrictions.

**Migrating from Terraform to OpenTofu:** change `native.type` in your `bricks.json` from `"terraform"` to `"opentofu"`. No code changes required since the syntax is identical.

## How to create this artifact

The only requirement is a directory where you can run `terraform plan` (or `tofu plan`). If your root module works locally, Bluebricks can use it as-is. Bluebricks auto-discovers your variables and outputs, manages state, and wires everything into blueprints.

You can create a Terraform/OpenTofu artifact in two ways:

* **In the Bluebricks app** during [blueprint creation](/docs/orchestration/packages/blueprints-overview/creating-blueprints.md): select your repository and directory containing the root module, and Bluebricks generates the artifact automatically
* **Via CLI**: run `bricks blueprint publish` from your root module directory. See [Creating Artifacts](/docs/orchestration/packages/artifacts-overview/creating-artifacts.md) for the full workflow, or [Publish a Terraform Module](/docs/orchestration/packages/artifacts-overview/terraform-open-tofu/publish-terraform-module.md) for the detailed step-by-step CLI guide

> The sections below explain how Bluebricks maps your code to inputs, outputs, and operations under the hood. Everything here is optional reading. To get started, head to [Creating Blueprints](/docs/orchestration/packages/blueprints-overview/creating-blueprints.md).

## Inputs

### What becomes an input

Terraform/OpenTofu `variable` blocks are auto-discovered and mapped to `props` in `bricks.json`:

```hcl
variable "region" {
  type    = string
  default = "us-east-1"
}

variable "vpc_cidr" {
  type = string
}
```

### How inputs are delivered at runtime

Bluebricks writes all props and secrets to a single auto-vars file:

| Runtime file                  | Contents                                                                                               |
| ----------------------------- | ------------------------------------------------------------------------------------------------------ |
| **`0_bbx_props.auto.tfvars`** | All props and secrets. Mark secret variables `sensitive = true` in HCL to keep them out of CLI output. |

Secrets never appear in logs and Bluebricks wipes them from the runner after completion.

## Outputs

### What becomes an output

Terraform/OpenTofu `output` blocks are auto-discovered and mapped to `outs` in `bricks.json`:

```hcl
output "vpc_id" {
  value     = aws_vpc.main.id
  sensitive = false
}
```

### How outputs are captured

After a successful apply, Bluebricks runs `terraform output -json` to capture all output values. During planning, output keys appear as "known after apply" placeholders.

### Referencing outputs downstream

In a blueprint, reference a Terraform output from another package using `Data.network_stack.vpc_id`.

## Supported operations

| Operation         | What it does                                                                                  |
| ----------------- | --------------------------------------------------------------------------------------------- |
| **Plan**          | Initializes providers, generates a plan showing resource actions and placeholder outputs      |
| **Apply**         | Executes the plan, captures real outputs, and uploads the final state                         |
| **Plan Destroy**  | Generates a plan showing everything that will be removed                                      |
| **Apply Destroy** | Executes the destroy plan and deletes the remote state. The environment is marked *Destroyed* |

## Managed state

Bluebricks manages the Terraform backend automatically. State is locked during applies (only one apply at a time), encrypted at rest and in transit, and compared against live resources on every plan to surface drift in the UI. If `state_path` is set in `bricks.json`, the file is imported on the first apply and then removed.

## Best practices

* Mark secrets as `sensitive = true` in variables to suppress them in CLI output, logs, and state
* Run `terraform validate` locally before pushing an artifact
* Pin provider versions in `required_providers` to avoid unexpected upgrades

## See also

* [Publish a Terraform Module](/docs/orchestration/packages/artifacts-overview/terraform-open-tofu/publish-terraform-module.md): step-by-step CLI publishing workflow
* [Develop Terraform Locally](https://bluebricks.co/docs/help/guides/develop-terraform-locally): work with remote state locally (Help Center)
* [Migrate Terraform State to Bluebricks](https://bluebricks.co/docs/help/guides/migrate-terraform-state): import existing state (Help Center)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bluebricks.co/docs/orchestration/packages/artifacts-overview/terraform-open-tofu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
