Skip to content

Terraform — How It Works

Provider plugin architecture, state management, plan/apply lifecycle, and dependency graph.

Core Lifecycle

sequenceDiagram
    participant User as User
    participant CLI as Terraform CLI
    participant State as State File
    participant Provider as Provider Plugin (gRPC)
    participant Cloud as Cloud API

    User->>CLI: terraform plan
    CLI->>State: Read current state
    CLI->>Provider: Refresh resource statuses
    Provider->>Cloud: API calls to check real state
    Provider-->>CLI: Current state
    CLI->>CLI: Diff: desired (HCL) vs current
    CLI-->>User: Execution plan (+ / ~ / -)

    User->>CLI: terraform apply
    CLI->>CLI: Build dependency graph (DAG)
    CLI->>Provider: Create/Update/Delete resources
    Provider->>Cloud: API calls
    Provider-->>CLI: Resource attributes
    CLI->>State: Write updated state

Dependency Graph (DAG)

Terraform builds a Directed Acyclic Graph of all resources, ensuring correct ordering:

flowchart TB
    VPC["aws_vpc"] --> Subnet["aws_subnet"]
    Subnet --> SG["aws_security_group"]
    Subnet --> Instance["aws_instance"]
    SG --> Instance
    Instance --> EIP["aws_eip"]

    style VPC fill:#ff6f00,color:#fff

Resources without dependencies are created in parallel.

Provider Plugin Architecture

flowchart LR
    CLI_T["Terraform CLI\n(core engine)"] <-->|"gRPC"| AWS["AWS Provider\n(plugin binary)"]
    CLI_T <-->|"gRPC"| GCP["GCP Provider"]
    CLI_T <-->|"gRPC"| K8s_P["K8s Provider"]
    CLI_T <-->|"gRPC"| Custom["Custom Provider"]

    style CLI_T fill:#7b42bc,color:#fff

Each provider is a separate binary communicating via gRPC. Providers are downloaded during terraform init from the Terraform Registry.

State File

Aspect Detail
Purpose Maps HCL resources to real-world objects
Format JSON (human-readable but not for editing)
Locking DynamoDB (AWS), GCS, Consul for remote
Sensitive data ⚠️ Stored in plaintext (use remote backend + encryption)
Remote backends S3, GCS, Azure Blob, Terraform Cloud, Consul

Sources