# Terraform Administrator & Architecture Guide

This guide is the deep, source-based reference for operators, platform engineers, and architects who deploy, integrate, secure, and extend Terraform — and for anyone who needs to understand how Terraform core actually works internally. It complements the [User Guide](/guides/hashicorp/terraform/user-guide/), which covers day-to-day CLI usage. Where the User Guide shows you *how to drive* Terraform, this guide explains *how it is built, what it requires, how to run it at scale, and how to keep it secure*.

It documents Terraform `1.16.0-dev` (Go `1.25.10`, license [BUSL-1.1](https://github.com/hashicorp/terraform/blob/main/LICENSE)). This repository is **Terraform core only**: the command-line interface and the graph engine. All cloud-specific logic lives in external *provider* plugins.

---

## 1. Executive Summary

Terraform is a single, statically-linked Go binary that turns declarative HCL configuration into ordered API calls against infrastructure platforms. Its defining architectural decisions are:

- **Declarative + graph-based.** Terraform builds a directed acyclic graph (DAG) of all resources and their dependencies, then walks it with bounded parallelism (default 10) to create, update, or destroy objects in the correct order.
- **Plan/apply separation.** Every change is first computed as a *plan* (a reviewable diff) and only then *applied*. Plans can be saved to a file and applied verbatim.
- **Core/plugin split over gRPC.** Terraform core contains no provider logic. Each provider and provisioner runs as a **separate OS process**, launched by core and driven over a gRPC protocol (`go-plugin`). This is why providers are independently versioned binaries downloaded from a registry.
- **State as the source of record.** Terraform records the mapping between configuration and real objects in *state*, stored locally or in one of 14 pluggable backends, with locking to make team workflows safe.

| Property | Value |
|----------|-------|
| Language | Go `1.25.10` |
| Binary | Single static `terraform` executable |
| Entry point | `main.go` → `realMain()` → `github.com/hashicorp/cli` runner |
| Core engine | `internal/terraform` (251 files, ~3.6M chars) — the `Context` + graph |
| Config language | HCL v2 (`github.com/hashicorp/hcl/v2 v2.24.0`) |
| Value/type system | `github.com/zclconf/go-cty` |
| Plugin transport | gRPC via `github.com/hashicorp/go-plugin v1.7.0` |
| Top-level commands | ~45 (registered in `commands.go`) |
| Built-in backends | 14 |
| Built-in provisioners | 3 (`file`, `local-exec`, `remote-exec`) |
| Built-in provider | 1 (`terraform`: `terraform_data`, `terraform_remote_state`) |
| Built-in functions | 116 |
| License | Business Source License 1.1 (source-available, not OSI open source) |

---

## 2. Architecture

### 2.1 High-level component map

```text
                         ┌───────────────────────────────────────────────┐
   terraform CLI         │  main.go → realMain()                          │
   (package main)        │   • LoadConfig (CLI config, ~/.terraformrc)    │
                         │   • service discovery + credentials (svchost)  │
                         │   • providerSource / providerDevOverrides      │
                         │   • backendInit.Init(services)                 │
                         │   • initCommands() → Commands map              │
                         │   • hashicorp/cli runner dispatches subcommand │
                         └───────────────────┬───────────────────────────┘
                                             │ command.Meta (shared deps)
                  ┌──────────────────────────┼──────────────────────────┐
                  ▼                          ▼                           ▼
        ┌──────────────────┐     ┌───────────────────────┐    ┌──────────────────┐
        │ internal/command │     │  internal/configs     │    │ internal/backend │
        │  ~45 commands +  │     │  HCL parse → Config    │    │ local/remote/s3/ │
        │  arguments/views │     │  (blocks, schema)      │    │ gcs/azurerm/...  │
        └────────┬─────────┘     └───────────┬───────────┘    └────────┬─────────┘
                 │                            │                         │
                 ▼                            ▼                         ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │                       internal/terraform                             │
        │   Context.{Plan,Apply,Refresh,Validate,Import,Eval}                  │
        │   GraphBuilder (plan/apply/eval/init) → applies ~58 Transformers     │
        │   → DAG (internal/dag) → graph walk (parallelism N) → node Execute   │
        └───────────┬───────────────────────────────────┬─────────────────────┘
                    │ providers.Interface               │ states / plans
                    ▼                                    ▼
        ┌────────────────────────────┐      ┌────────────────────────────────┐
        │ internal/plugin (+plugin6)  │      │ internal/states, internal/plans │
        │ GRPCProvider over go-plugin │      │ state model, planfile, diffs    │
        │ tfplugin5 / tfplugin6 stubs │      └────────────────────────────────┘
        └────────────┬───────────────┘
                     │ gRPC (separate process per plugin)
                     ▼
        ┌────────────────────────────┐
        │  Provider plugin binary     │  (aws, azurerm, google, kubernetes…)
        │  downloaded via registry    │
        └────────────────────────────┘
```

### 2.2 The `Context` — the core engine

The heart of Terraform is `terraform.Context` in `internal/terraform`. It is constructed with `NewContext(*ContextOpts)` (where `Parallelism` is set) and exposes the operations that every CLI command ultimately calls:

| Method | Purpose |
|--------|---------|
| `Context.Validate` | Static validation of a configuration. |
| `Context.Plan` | Compute a plan (create/update/destroy/replace) from config + prior state + refreshed reality. |
| `Context.Apply` | Execute a plan, producing new state. |
| `Context.Refresh` | Update state to match real infrastructure (no config changes). |
| `Context.Import` | Bring an existing object into state. |
| `Context.Eval` | Evaluate expressions (used by `terraform console`). |
| `Context.Schemas` | Resolve provider/provisioner schemas. |
| `Context.Stop` | Gracefully interrupt an in-flight walk (wired to SIGINT). |

### 2.3 Graph construction and the walk

Terraform models every operation as a graph. The flow is:

1. **Parse** — `internal/configs` reads `.tf`/`.tf.json` into a `configs.Config` tree (root module + descendants). `BuildConfigWithGraph` resolves module sources/versions with full expression evaluation before loading descendants.
2. **Build** — an operation-specific **GraphBuilder** (`graph_builder_plan.go`, `graph_builder_apply.go`, `graph_builder_eval.go`, `graph_builder_init.go`) produces the graph by applying a pipeline of **~58 transformers** (`transform_*.go`). Transformers add nodes for resources, providers, provisioners, variables, outputs, locals, module expansion (`count`/`for_each`), and then wire edges for references, `depends_on`, provider attachment, destroy ordering, pruning, and more.
3. **Reduce** — the graph is transitively reduced and validated as a DAG (`internal/dag`), which detects cycles (surfaced as `Error: Cycle: ...`).
4. **Walk** — the DAG is walked concurrently with up to `Parallelism` (default 10) workers. Each node's `Execute` runs in dependency order. The walk type selects behavior: `walkPlan`, `walkApply`, `walkDestroy`, `walkPlanDestroy`, `walkValidate`, `walkImport`, `walkEval`.

> [!NOTE]
> Because ordering is derived from the graph, you rarely need `depends_on`. Implicit dependencies (attribute references like `aws_instance.web.id`) create graph edges automatically and are preferred.

### 2.4 The provider/provisioner plugin protocol

Providers and provisioners are **out-of-process gRPC servers**. Core is the client.

- **Transport:** `github.com/hashicorp/go-plugin`. Core launches the plugin binary as a child process; the plugin performs a handshake (magic cookie + protocol version) over stdio, then serves gRPC on a local socket. `plugin.CleanupClients()` (deferred in `realMain`) tears down all plugin processes at exit.
- **Protocol versions:** `internal/tfplugin5` (protocol 5) and `internal/tfplugin6` (protocol 6) hold the generated gRPC stubs. `internal/plugin` and `internal/plugin6` wrap them as `providers.Interface` via `GRPCProvider`.
- **Provider RPCs** include `GetProviderSchema`, `ValidateProviderConfig`, `ConfigureProvider`, `ReadResource`, `PlanResourceChange`, `ApplyResourceChange`, `ImportResourceState`, `ReadDataSource`, and `GetResourceIdentitySchemas`.
- **Values on the wire:** all values are `go-cty` values serialized as **msgpack**. Marks carry sensitivity and ephemerality across the boundary.

This isolation is a deliberate reliability and security boundary: a crashing provider cannot corrupt core's memory, and `internal/logging` surfaces plugin panics separately (`PluginPanics()`).

### 2.5 Built-in plugins

A few plugins are compiled into core and served from sub-binaries for testing:

- **Built-in provider** `terraform` (`internal/builtin/providers/terraform`): supplies `terraform_data` (a managed resource for arbitrary values, including the new ephemeral/sensitive `store` block in 1.16) and the `terraform_remote_state` data source.
- **Built-in provisioners** (`internal/builtin/provisioners`): `file`, `local-exec`, `remote-exec`. The latter two use `internal/communicator` for SSH/WinRM.

---

## 3. Repository & Component Inventory

The codebase is overwhelmingly under `internal/` (Go's enforced-private boundary). The largest and most important packages:

| Package | Files | ~Chars | Role |
|---------|-------|--------|------|
| `internal/terraform` | 251 | 3.6M | Core engine: `Context`, graph builders, transformers, walk. |
| `internal/command` | 124 | 2.0M | All CLI command implementations, `Meta`, `arguments/`, `views/`. |
| `internal/configs` | 63 | 661K | HCL parsing into the configuration model; block schemas. |
| `internal/cloud` | 41 | 575K | HCP Terraform / Terraform Enterprise integration. |
| `internal/addrs` | 67 | 461K | Address types (resource, module, provider, etc.). |
| `internal/tfplugin6` | 3 | 389K | Protocol v6 gRPC stubs. |
| `internal/tfplugin5` | 3 | 341K | Protocol v5 gRPC stubs. |
| `internal/rpcapi` | 27 | 286K | gRPC API for HCP Terraform automation (internal). |
| `internal/getproviders` | 28 | 262K | Provider discovery, registry protocol, installation. |
| `internal/backend/remote` | 18 | 239K | Remote backend (HCP Terraform). |
| `internal/legacy/helper/schema` | 42 | 200K | Legacy SDK schema helpers. |
| `internal/providercache` | 13 | 191K | Provider cache and the dependency lock file. |
| `internal/plugin6` / `internal/plugin` | 5 / 11 | 163K / 123K | gRPC provider/provisioner clients. |
| `internal/states` | 16 | 148K | State model and serialization. |
| `internal/plans` | 20 + planproto | 106K+ | Plan model and the plan-file format. |
| `internal/dag` | 18 | 90K | Directed acyclic graph implementation. |
| `internal/stacks/*`, `internal/rpcapi/*` | — | — | Experimental "stacks" runtime (HCP Terraform). |

Other notable packages: `internal/lang` (expression/function evaluation, the 116-function registry), `internal/instances` (`count`/`for_each` expansion), `internal/refactoring` (`moved`/`removed` blocks), `internal/moduletest` (the `test` framework), `internal/genconfig` (config generation for import), `internal/checks` (`check` blocks / pre/postconditions), and `internal/terminal` (TTY handling).

> [!NOTE]
> The `internal/` prefix means none of these packages are importable by third parties — Terraform core is explicitly **not** a public Go library. Integrations should use the CLI, the JSON output formats, or (for HCP Terraform) the `rpcapi`.

---

## 4. System Requirements

| Concern | Requirement |
|---------|-------------|
| OS | Linux, macOS, Windows, FreeBSD, Solaris; many architectures including `amd64`, `arm64`, and Linux `s390x` (zLinux). |
| Runtime | None — single static binary. (Building from source requires Go `1.25.10`.) |
| Memory | Scales with configuration and state size; modest for typical configs, larger for thousands of resources. |
| Network | Outbound HTTPS to provider/module registries (`registry.terraform.io`) during `init`; outbound to provider target APIs during plan/apply; outbound to HCP Terraform if using the `cloud`/`remote` backend. |
| Disk | `.terraform/` per working directory holds installed providers (can be large); a shared plugin cache mitigates duplication. |
| External tools | Optional: `git`/SSH for Git module sources; GraphViz `dot` to render `terraform graph`. |

---

## 5. Configuration Mastery

There are three distinct configuration surfaces an administrator manages: the **CLI configuration file** (machine-wide behavior), the **backend configuration** (where state lives), and **environment variables** (per-run overrides).

### 5.1 The CLI configuration file

Loaded by `cliconfig.LoadConfig()` at startup (before `-chdir` is applied). Location:

- Linux/macOS: `~/.terraformrc`
- Windows: `%APPDATA%\terraform.rc`
- Override path: `TF_CLI_CONFIG_FILE` (historically `TERRAFORM_CONFIG`).

Key settings:

```hcl
# Reuse downloaded providers across all working directories
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"

# Control where providers are installed from
provider_installation {
  network_mirror {
    url = "https://terraform.example.com/providers/"
  }
  direct {
    exclude = ["registry.terraform.io/*/*"]
  }
}

# Pin a locally-built provider for development
provider_installation {
  dev_overrides {
    "example.com/acme/foo" = "/home/dev/go/bin"
  }
  direct {}
}

# Credentials for a host (prefer `terraform login` or env vars)
credentials "app.terraform.io" {
  token = "REDACTED"
}
```

> [!TIP]
> `plugin_cache_dir` is the single highest-impact operational setting for CI and multi-directory monorepos — it eliminates redundant provider downloads. Set `PluginCacheMayBreakDependencyLockFile` (or the equivalent CLI flag) only if you understand the lock-file trade-off.

### 5.2 Provider installation methods

`terraform init` resolves providers through the `provider_installation` block (above) or, by default, directly from registries. For air-gapped or controlled environments:

| Method | Command / config | Use case |
|--------|------------------|----------|
| Direct from registry | default | Internet-connected environments. |
| Filesystem mirror | `terraform providers mirror <dir>` then `filesystem_mirror` | Air-gapped install from a local directory. |
| Network mirror | publish the mirror output over HTTP + `network_mirror` | Centralized, controlled distribution. |
| Dev override | `dev_overrides` | Local provider development (skips the lock file). |
| Plugin dir | `terraform init -plugin-dir=DIR` | Force a single source; disables auto-install. |

The dependency lock file `.terraform.lock.hcl` (managed by `internal/providercache`) records selected versions and **per-platform checksums**. Use `terraform providers lock -platform=os_arch ...` to populate checksums for every platform your team and CI use, so `init` succeeds everywhere.

### 5.3 Backend configuration reference

Backends are registered by `backendInit.Init()` and configured in the `terraform` block. The 14 built-in backends:

| Backend | Locking | Notes |
|---------|---------|-------|
| `local` | OS file lock | Default. State in `terraform.tfstate`. |
| `remote` | Yes (HCP) | HCP Terraform / Terraform Enterprise, optional remote execution. |
| `cloud` | Yes (HCP) | Configured via the `cloud {}` block rather than `backend`. |
| `s3` | DynamoDB or S3-native | Most common AWS backend; supports KMS encryption. |
| `gcs` | Yes | Google Cloud Storage. |
| `azurerm` | Yes (blob lease) | Azure Blob Storage. |
| `oss` | Yes (via OTS/table) | Alibaba Cloud OSS. |
| `cos` | Yes | Tencent Cloud COS. |
| `oci` | Yes | Oracle Cloud Object Storage. |
| `consul` | Yes | HashiCorp Consul KV. |
| `kubernetes` | Yes (lease) | Kubernetes Secrets. |
| `pg` | Yes (advisory lock) | PostgreSQL. |
| `http` | Optional | Generic REST backend (`LOCK`/`UNLOCK` verbs). |
| `inmem` | Yes | In-memory; testing only. |

Provide secrets and dynamic values via `-backend-config` (file or `key=value`) at `init` time rather than committing them:

```bash
terraform init -backend-config=backend-prod.hcl
terraform init -backend-config="bucket=my-state" -backend-config="region=us-east-1"
```

### 5.4 Environment variables (operational set)

See the User Guide §14 for the full list. The ones most relevant to operators:

| Variable | Effect |
|----------|--------|
| `TF_DATA_DIR` | Relocate the `.terraform` working directory (read in `commands.go`). |
| `TF_IN_AUTOMATION` | Tidy output for CI; set by the `TF_IN_AUTOMATION` check in `commands.go`. |
| `TF_CLI_ARGS` / `TF_CLI_ARGS_<cmd>` | Inject default arguments globally or per subcommand. |
| `TF_LOG` / `TF_LOG_PATH` | Logging level and destination (`internal/logging`). |
| `TF_PLUGIN_CACHE_DIR` | Plugin cache directory (env equivalent of `plugin_cache_dir`). |
| `TF_FORCE_LOCAL_BACKEND` | Force local operations despite a `cloud` block (`internal/cloud/backend.go`). |
| `TF_REATTACH_PROVIDERS` | Attach to externally-running providers (acceptance testing / debugging). |

---

## 6. The Plan/Apply Lifecycle (Internals)

```text
  CONFIG (*.tf)            PRIOR STATE              REAL INFRASTRUCTURE
       │                       │                            │
       ▼                       ▼                            │
  configs.Config  ──┐    states.State                       │
                    │         │                             │
                    ▼         ▼                             ▼
              Context.Plan ── refresh (ReadResource via provider gRPC) ◀┘
                    │
                    ▼
      GraphBuilder(plan) → transformers → DAG → walkPlan
                    │   (PlanResourceChange RPC per resource)
                    ▼
              plans.Plan  ──(optional)──▶  plan file (planfile, planproto)
                    │
                    ▼
              Context.Apply → GraphBuilder(apply) → walkApply
                    │   (ApplyResourceChange RPC per resource, parallelism N)
                    ▼
              NEW states.State  ──▶  persisted via backend (with lock)
```

Key points for operators:

- **Refresh** happens by default during plan (disable with `-refresh=false`; review-only with `-refresh-only`). It issues `ReadResource` RPCs and can be slow for large states.
- **Parallelism** (`-parallelism=n`, default 10) bounds concurrent provider RPCs during the walk. Lower it to relieve API rate limits; raise it cautiously for throughput.
- **Saved plans** (`-out`) capture the exact intended changes; `apply <planfile>` replays them with no prompt. Plans go stale if state changes underneath them (`Saved plan is stale`).
- **Targeting** (`-target`) prunes the graph to a subset; it is an escape hatch, not a workflow.
- **Detailed exit codes** (`-detailed-exitcode`: `0`/`1`/`2`) drive CI gating.

---

## 7. State Management (Operations)

State (`internal/states`) is Terraform's record of managed objects. Treat it as sensitive, authoritative, and fragile.

### 7.1 Safe operations

- All `terraform state` mutating subcommands **write a timestamped backup first** (this cannot be disabled for `state mv`).
- State **locking** prevents concurrent writers. The lock mechanism is backend-specific (DynamoDB, blob lease, advisory lock, etc.). `terraform force-unlock LOCK_ID` releases a stuck lock — only when you are certain nothing is running.
- `terraform state pull` / `push` move whole state documents; `push` refuses older serials or mismatched lineage unless `-force` is given.

### 7.2 Routine state hygiene

| Task | Command |
|------|---------|
| Inspect | `terraform state list`, `terraform state show ADDR`, `terraform show -json` |
| Refactor address | `terraform state mv` or a `moved {}` block (preferred — reviewable). |
| Forget without destroying | `terraform state rm ADDR` or a `removed {}` block. |
| Re-home a provider | `terraform state replace-provider FROM TO`. |
| Recover drift | `terraform plan -refresh-only`, then apply or correct reality. |

> [!WARNING]
> State frequently contains secrets (passwords, private keys, tokens) in plaintext. Always use a remote backend with encryption at rest and access controls for anything beyond local experimentation. Restrict who can read the state bucket/store as tightly as who can deploy. (See GitHub issue #34860 — minimizing secrets in state — for the ongoing upstream effort.)

---

## 8. Security

### 8.1 Threat surfaces and controls

| Surface | Risk | Control |
|---------|------|---------|
| **State** | Plaintext secrets, tamper, deletion | Encrypted remote backend, least-privilege IAM, versioning, backups. |
| **Provider plugins** | Malicious or tampered binaries | Lock-file checksums (`.terraform.lock.hcl`), signed registry packages, filesystem/network mirrors you control. |
| **Plugin transport** | MITM on local gRPC | TLS by default; `TF_DISABLE_PLUGIN_TLS` disables it — **dev only**. |
| **Credentials** | Leaked tokens | `terraform login` stores tokens in a credentials file; prefer `TF_TOKEN_<host>` env vars or a credentials helper in CI. |
| **Provisioners** | Arbitrary command execution | Avoid where possible; treat `local-exec`/`remote-exec` scripts as code to review. |
| **Module sources** | Supply-chain (unpinned modules) | Pin `version`/`?ref=`; vendor or mirror critical modules. |
| **Sensitive values** | Accidental disclosure in output/logs | `sensitive = true`, the `sensitive()`/`nonsensitive()` functions, and ephemeral values (never written to state). |

### 8.2 Supply-chain integrity

- The dependency lock file records SHA256 checksums per platform; `init` verifies downloaded packages against them. Registry packages are GPG-signed (`internal/releaseauth` validates release authenticity).
- For regulated/air-gapped environments, run an internal network or filesystem mirror (`terraform providers mirror`) and set `provider_installation` to use only it.

### 8.3 Sensitive and ephemeral data

Terraform tracks sensitivity as a **mark** on `go-cty` values that propagates through expressions, so a value derived from a sensitive input stays sensitive. **Ephemeral** values (ephemeral resources/variables/outputs, and the `terraform_data` `store` block added in 1.16) exist only during a single operation and are **never persisted to state or plan files** — the correct mechanism for short-lived secrets.

> [!CAUTION]
> `sensitive = true` hides values from CLI output but they are **still stored in state in plaintext**. For secrets that must never touch state, use ephemeral values, not just the sensitive flag.

### 8.4 Licensing

Terraform is licensed under **BUSL-1.1**, a source-available license that prohibits offering a competing commercial service. This is not OSI-approved open source. Audit obligations before redistributing, embedding, or building a hosted service on Terraform.

---

## 9. Operations & Automation

### 9.1 Running in CI/CD

The canonical non-interactive pipeline:

```bash
terraform init -input=false -lock-timeout=120s
terraform fmt -check -recursive
terraform validate
terraform plan -input=false -lock-timeout=120s -out=tfplan -detailed-exitcode
# exit 0 = no changes, 2 = changes (apply), 1 = error
terraform apply -input=false tfplan
```

- Set `TF_IN_AUTOMATION=1` to suppress prompts-assuming messages.
- Use `-lock-timeout` so concurrent pipeline runs wait instead of failing.
- Provide variables via `TF_VAR_*` or `-var-file`; never echo secrets into logs.
- Persist `.terraform.lock.hcl` in the repo; CI should not silently upgrade providers.

### 9.2 Provider caching & throughput

- Set `plugin_cache_dir` / `TF_PLUGIN_CACHE_DIR` on CI images so providers are downloaded once.
- Bake the provider cache (and optionally a module mirror) into your CI base image for fully offline runs.
- Note GitHub issue #31964: concurrent writes to a shared `plugin_cache_dir` are not yet fully supported — give each concurrent runner its own cache, or pre-warm a read-only cache.

### 9.3 Logging & diagnostics

- `TF_LOG=TRACE|DEBUG|INFO|WARN|ERROR` plus `TF_LOG_PATH=run.log` capture detailed logs (`internal/logging`). The harness writes crash logs to `TF_TEMP_LOG_PATH` and surfaces plugin panics via `PluginPanics()`.
- `terraform graph -draw-cycles` diagnoses dependency cycles.
- `terraform providers schema -json` and `terraform metadata functions -json` give machine-readable schema/function references for editor and tooling integration.
- OpenTelemetry tracing is built in: `realMain` starts a root span per invocation (`terraform <args>`), configurable via the OTEL exporter environment variable.

### 9.4 HCP Terraform / Terraform Enterprise

The `cloud {}` block (or `remote` backend) delegates state storage and optionally **remote execution** to HCP Terraform (`internal/cloud`, client `go-tfe`). `terraform login`/`logout` manage tokens; `terraform-svchost` performs service discovery. Force local execution with `TF_FORCE_LOCAL_BACKEND`. The experimental `stacks` and `rpcapi` subsystems exist specifically to integrate HCP Terraform with core and are **not** intended for direct end-user use.

---

## 10. The Module Subsystem

Module installation is handled by `internal/initwd`, `internal/getmodules`, `internal/modsdir`, and `internal/registry`, built on `github.com/hashicorp/go-getter` and `go-slug`.

- **Source resolution:** local paths, Terraform Registry, Git (`git::`), HTTP archives, and S3/GCS objects — each handled by a go-getter detector/getter.
- **Manifest:** installed modules are recorded in `.terraform/modules/modules.json`; `terraform get -update` refreshes them within version constraints.
- **Refactoring:** `moved {}` blocks let you rename or re-parent resources across module boundaries without destroy/recreate (`internal/refactoring`). Terraform 1.16 adds support for `import` blocks **inside modules**.

> [!IMPORTANT]
> Always pin registry and Git modules (`version = "x.y.z"` or `?ref=tag`). Unpinned sources can change between runs, producing unexpected plans and breaking reproducibility — and are a supply-chain risk.

---

## 11. Code Quality, Patterns & Conventions

- **Strict internal boundary.** Nearly all code lives under `internal/`, enforcing that Terraform core is not a public library. Integrations go through the CLI, JSON outputs, or the HCP `rpcapi`.
- **Address types as a first-class package.** `internal/addrs` models every kind of address (resource, module instance, provider, etc.) with strong typing, avoiding stringly-typed bugs across the engine.
- **Transformer pipeline.** Graph construction is decomposed into ~58 small, composable transformers — each does one thing (add nodes of a kind, or wire one kind of edge). This makes the engine's behavior auditable and testable.
- **Diagnostics over errors.** `internal/tfdiags` provides rich diagnostics (severity, summary, detail, source location) used throughout, enabling the precise, snippet-annotated error output Terraform is known for.
- **Views/arguments separation.** Commands parse flags into typed `arguments.*` structs and render through `views.*`, cleanly separating input parsing, business logic, and output formatting (and enabling `-json` consistently).
- **Generated code.** The gRPC stubs (`tfplugin5`/`tfplugin6`/`planproto`) and the `dynrpcserver` wrappers are generated; `tools/protobuf-compile` and the `dynrpcserver/generator` drive this. Do not hand-edit generated files.

### 11.1 Testing strategy

- Extensive **fixture-driven** tests: the high file count is dominated by `internal/*/testdata/*` and `testing/equivalence-tests/*` — self-contained scenarios, not application code (a known characteristic of large Go repos).
- **Equivalence tests** (`testing/equivalence-tests`) snapshot plan/apply output to catch unintended changes in rendering and behavior.
- **End-to-end tests** (`internal/command/e2etest`, `internal/cloud/e2e`) exercise the real binary.
- Terraform also ships a user-facing test framework (`internal/moduletest`, `terraform test`).

---

## 12. Known Issues & Improvement Areas

Drawn from the project's own issue tracker and code structure — useful when planning rollouts.

| Area | Issue | Operational implication |
|------|-------|-------------------------|
| Shared plugin cache | #31964 | Concurrent runners writing one `plugin_cache_dir` can race; isolate caches. |
| Provider cache breakage | #32901 | `1.4.0+` changed shared-cache behavior; verify cache layout after upgrades. |
| Secrets in state | #34860 | No built-in secret stripping yet; rely on backend encryption + access control + ephemeral values. |
| Network mirror chaining | #36006, #31804 | Mirroring *from* a mirror and some mirror-protocol setups (e.g. Artifactory) are not fully supported/documented. |
| `prevent_destroy` ergonomics | #3874 | Cannot selectively allow some destroys; plan around it. |
| `import` edge cases | #38660, #38338 | Validate imports carefully; provider local names now respected (1.16 fix). |
| Deprecated-variable warnings | #38554 | Spurious warnings reported for unset deprecated variables. |

### 12.1 Notable 1.16 changes for operators

- `workspace list -json` and `state show -json` machine-readable output.
- `terraform_data` gains a `store` block for ephemeral/sensitive values.
- `import` blocks supported **inside modules**.
- Linux `s390x` builds published.
- Experimental (alpha builds only): deferred actions (`-allow-deferral`), `terraform test cleanup`, and `terraform test` `backend` blocks + `skip_cleanup`.
- Upgrade note: provisioner `bastion_host_key` is now correctly applied — verify your configured key is correct before upgrading.

---

## 13. Quick Reference

### 13.1 Operator command cheat-sheet

```bash
# Air-gapped provider install
terraform providers mirror /srv/tf-mirror
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64

# CI pipeline
terraform init -input=false -lock-timeout=120s
terraform plan -input=false -out=tfplan -detailed-exitcode
terraform apply -input=false tfplan

# Backend migration
terraform init -migrate-state            # move state to new backend
terraform init -reconfigure              # ignore old backend config

# State surgery (each backs up first)
terraform state mv A B
terraform state rm aws_instance.legacy
terraform force-unlock <LOCK_ID>

# Diagnostics
TF_LOG=DEBUG TF_LOG_PATH=tf.log terraform plan
terraform graph -draw-cycles | dot -Tsvg > graph.svg
terraform providers schema -json | jq
```

### 13.2 Architecture facts

| Question | Answer |
|----------|--------|
| Where do commands register? | `commands.go` → `Commands map[string]cli.CommandFactory`. |
| What runs an operation? | `terraform.Context.{Plan,Apply,Refresh,Validate,Import,Eval}`. |
| How is the graph built? | Operation-specific `GraphBuilder` applies ~58 `transform_*` transformers → `internal/dag`. |
| How are providers run? | Separate process, gRPC via `go-plugin`, protocol `tfplugin5`/`tfplugin6`, msgpack `cty` values. |
| Where is state defined? | `internal/states`; persisted by one of 14 backends. |
| Where is the config language? | `internal/configs` (parsing) + `internal/lang` (evaluation), built on HCL v2 + go-cty. |
| Default parallelism? | 10 (`-parallelism`). |

### 13.3 Key file/dir glossary

| Path | Meaning |
|------|---------|
| `.terraform/` | Per-directory working data (providers, modules, backend config). |
| `.terraform.lock.hcl` | Provider dependency lock (versions + checksums). |
| `terraform.tfstate` | Local state (default backend). |
| `~/.terraformrc` / `%APPDATA%\terraform.rc` | CLI configuration file. |
| `*.tfbackend` | Conventional name for `-backend-config` files. |

---

_Generated June 2026 from hashicorp/terraform at b2fc2ca. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
