← Back to list

Terraform Mental Models Series — Episode 1: What Actually Happens During Init, Plan, and Apply

Most Terraform tutorials introduce three commands almost immediately:

Alkayedayat · 2026-06-12 21:37 · 0 claps · 5.6 min read
#terraform #iac #cloud-automation
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 🥊 · Combat Sports

Terraform Mental Models Series — Episode 1: What Actually Happens During Init, Plan, and Apply

Most Terraform tutorials introduce three commands almost immediately:

terraform init
terraform plan
terraform apply

They’re usually explained like this:

  • terraform init initializes Terraform
  • terraform plan shows what will change
  • terraform apply creates or updates infrastructure

While that’s technically correct, it doesn’t explain what Terraform is actually doing.

And if you’ve ever wondered why Terraform needs a state file, downloads providers, builds dependency graphs, or sometimes shows values as (known after apply), those simple explanations quickly stop being enough.

The reality is that Terraform does far more than execute infrastructure commands.

Terraform isn’t a script runner.

Terraform is a reconciliation engine.

Its job is not to create infrastructure.

Its job is to continuously reconcile the infrastructure you want with the infrastructure that actually exists.

Understanding that mental model makes many of Terraform’s behaviors much easier to understand.

Why Understanding This Matters

Understanding what happens behind the scenes isn’t just an academic exercise.

These internals explain many of Terraform’s most confusing behaviors:

  • Why Terraform sometimes replaces resources unexpectedly
  • Why state corruption can be catastrophic
  • Why dependency cycles occur
  • Why some values are unknown during planning
  • Why provider upgrades can change execution behavior
  • Why moving resources between count and for_each can trigger replacements

The better you understand Terraform’s internals, the easier it becomes to:

  • Troubleshoot failed deployments
  • Review plans with confidence
  • Design reusable modules
  • Build safer CI/CD pipelines
  • Avoid costly infrastructure mistakes

The Mental Model Most Engineers Miss

Many engineers unconsciously think Terraform works like this:

Configuration
      ↓
Create Infrastructure

But that’s not what happens.

Terraform actually works with three different realities.

1. Desired State

This is your Terraform configuration.

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

Your configuration describes what should exist.

It describes the end state, not the steps required to get there.

2. Recorded State

This is Terraform’s memory.

Usually stored in:

terraform.tfstate

Terraform uses state to remember which resources it manages and how those resources map to your configuration.

Without state, Terraform has no memory of previous deployments.

3. Actual Infrastructure

This is what currently exists inside AWS, Azure, GCP, or another provider.

Terraform retrieves this information directly from provider APIs.

Every Terraform operation is ultimately trying to answer one question:

How do I make actual infrastructure match the desired state described in my configuration?

Everything else exists to answer that question safely and predictably.

What Actually Happens During Terraform Init

When you run:

terraform init

Terraform prepares its working environment.

No infrastructure changes occur.

No resources are created.

Instead, Terraform gathers everything it needs before it can reason about infrastructure.

Provider Installation

Terraform itself doesn’t know how to create an EC2 instance.

It doesn’t know how to create a VPC.

It doesn’t know how to create anything in AWS.

That responsibility belongs to providers.

Consider:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

During initialization, Terraform downloads the required provider plugins.

A useful mental model is:

Terraform Core = Brain
Provider = Translator
Cloud API = Worker

Terraform decides what should happen.

The provider knows how to communicate with the cloud platform.

Without providers, Terraform has no way to interact with infrastructure.

Backend Initialization

Terraform also initializes the backend.

For example:

terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-east-1"
  }
}

The backend determines where Terraform stores its state.

This could be:

  • Local disk
  • Amazon S3
  • Azure Storage
  • Google Cloud Storage
  • Terraform Cloud

If a remote backend is configured, Terraform retrieves the latest state.

Working Directory Preparation

Terraform creates the .terraform directory and updates:

.terraform.lock.hcl

The lock file records the exact provider versions being used.

This helps ensure that every engineer and every CI/CD pipeline uses the same provider versions.

What Actually Happens During Terraform Plan

Many engineers describe terraform plan as a dry run.

That’s true.

But it’s only part of the story.

The interesting part is how Terraform produces the plan.

Terraform Loads State

State is what allows Terraform to connect configuration to real infrastructure.

When Terraform loads state, it isn’t simply reading a file.

It’s loading its memory of the infrastructure it manages.

Terraform then compares:

  • Desired state (configuration)
  • Recorded state (state file)
  • Actual state (provider APIs)

The differences between those three realities become the execution plan.

Without state, Terraform would have no reliable way to understand what changed.

Terraform Queries the Provider

Terraform retrieves information about the actual infrastructure through provider APIs.

For AWS, that means communicating through the AWS provider.

Terraform now has access to:

  • What you want
  • What it remembers
  • What actually exists

Only now can Terraform begin calculating changes.

Terraform Builds a Dependency Graph

This is one of Terraform’s most important internal concepts.

Consider:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "app" {
  vpc_id = aws_vpc.main.id
}

Terraform sees:

aws_vpc.main.id

and automatically discovers a dependency.

Internally it builds something similar to:

aws_vpc.main
       ↓
aws_subnet.app

References like:

aws_vpc.main.id

don’t just provide values.

They also tell Terraform how resources are related.

Those relationships become edges in the dependency graph.

Terraform does not execute resources based on file order.

It executes resources based on dependency relationships.

This dependency graph becomes Terraform’s execution blueprint.

Terraform Creates an Execution Plan

Once Terraform understands:

  • Desired state
  • Current state
  • Resource dependencies

it calculates the required actions.

Example:

Plan: 2 to add, 1 to change, 0 to destroy.

This isn’t simply a preview.

It’s Terraform’s decision document.

The plan represents Terraform’s understanding of how reality must change to match the desired state.

Why Some Values Are Unknown

You’ve probably seen output like:

(known after apply)

For example:

resource "aws_instance" "web" {
  ami           = "ami-123"
  instance_type = "t3.micro"
}

AWS generates the instance ID during creation.

Terraform cannot know that value beforehand.

So during planning Terraform marks it as unknown.

This isn’t Terraform being uncertain.

It’s Terraform being honest about what information exists and what information doesn’t exist yet.

Saving a Frozen Execution Plan

Terraform can save a plan to a file:

terraform plan -out=tfplan

Later:

terraform apply tfplan

This is common in production environments.

Why?

Because the exact plan that was reviewed becomes the exact plan that gets executed.

No surprises.

No last-minute changes.

No accidental modifications.

This approach is widely used in approval workflows and CI/CD pipelines.

What Actually Happens During Terraform Apply

When you run:

terraform apply

Terraform executes the actions calculated during planning.

Most of the difficult work has already been completed.

Providers Call Cloud APIs

Terraform itself never talks directly to AWS.

Instead:

Terraform Core
        ↓
AWS Provider
        ↓
AWS API
        ↓
Resource Creation

The provider translates Terraform operations into cloud API requests.

Terraform Follows the Dependency Graph

Remember the dependency graph Terraform built during planning?

Terraform now follows that graph.

For example:

VPC
 ↓
Subnet
 ↓
EC2 Instance

Resources are created according to dependency relationships.

Not file order.

Not resource block order.

Graph order.

Parallel Execution

If two resources are completely independent:

S3 Bucket
IAM Role

Terraform can create them simultaneously.

However, dependencies limit parallelism.

Resources that depend on one another must still be executed sequentially, regardless of where they appear in the configuration.

This is one reason Terraform deployments are often much faster than engineers expect.

Terraform is executing a graph, not reading a script line by line.

State Is Updated

After changes complete successfully, Terraform updates the state.

The state file becomes Terraform’s new understanding of reality.

Future plans will use this updated state as their baseline.

Importantly, state isn’t updated only when resources are created.

Terraform updates state whenever resources are:

  • Created
  • Modified
  • Destroyed

The state file is not a deployment artifact.

It’s Terraform’s continuously evolving understanding of the infrastructure it manages.

The Workflow Most Engineers Never Visualize

Most people think Terraform works like this:

terraform init
      ↓
terraform plan
      ↓
terraform apply

Internally, the workflow looks more like this:

Configuration
       │
       ▼
terraform init
       │
       ▼
Providers + Backend + State
       │
       ▼
terraform plan
       │
       ▼
Dependency Graph
       │
       ▼
Execution Plan
       │
       ▼
terraform apply
       │
       ▼
Cloud APIs
       │
       ▼
Updated State

Terraform spends far more time reasoning about infrastructure than creating it.

Final Thoughts

Terraform’s biggest strength isn’t that it can create infrastructure.

Every cloud platform already provides APIs for that.

Terraform’s real strength is its ability to continuously reconcile desired infrastructure with reality.

That’s why state exists.

That’s why plans exist.

That’s why dependency graphs exist.

That’s why providers exist.

Terraform isn’t applying your configuration.

Terraform is continuously trying to answer a much harder question:

Given what I want, what I remember, and what actually exists, what must change?

Everything else — providers, state files, plans, dependency graphs, and applies — exists to answer that question.

And once you understand that, many of Terraform’s most confusing behaviors suddenly start making sense.


메타데이터
post_id
4c3984f0fb8e
slug
terraform-mental-models-series-episode-1-what-actually-happens-during-init-plan-and-apply-4c3984f0fb8e
url
https://medium.com/@alkayedayat93/terraform-mental-models-series-episode-1-what-actually-happens-during-init-plan-and-apply-4c3984f0fb8e
canonical_url
https://medium.com/@alkayedayat93/terraform-mental-models-series-episode-1-what-actually-happens-during-init-plan-and-apply-4c3984f0fb8e
author_url
https://medium.com/@alkayedayat93
status
ok
fetched_at
2026-06-13 12:55:53