Jesse A. Green / notebook

Terraform Administrator & Architecture Guide

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.

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, 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). 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

                         ┌───────────────────────────────────────────────┐
   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:

# 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:

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)

  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:

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

# 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.