Lesson 3 · Terraform fundamentals

State

Terraform's memory of the real world — the file that makes plan/apply possible, and the one you must not lose.

Your win: explain what Terraform state is and why it's the source of truth, why it must be remote and locked for a team, and what drift is — using this repo's GCS backend.

Why Terraform needs to remember

When you run plan, Terraform compares three things: your config (desired), the real infrastructure (actual), and its state — its own record of what it created last time.1 Without state, Terraform couldn't tell "create a new bucket" from "this bucket already exists, leave it" — every apply would try to recreate everything. State is Terraform's memory, and its source of truth for the diff.

State is precious — and a little dangerous The state file maps your config to real resource IDs. Lose it and Terraform "forgets" it owns your infrastructure (and may try to recreate it). Corrupt it and plans go wrong. It can also contain secrets (a generated DB password ends up in state). So state is treated carefully: stored remotely, locked, versioned — never a loose file on someone's laptop.

Remote state — one shared truth

A local terraform.tfstate file works for one person. A team (and an automation like Atlantis) needs remote state: a shared backend — here a GCS bucket — so everyone diffs against the same truth, with versioning and encryption.2

Anchor — the GCS backend, configured once deployments/terraform/live/root.hcl:11-23 declares the remote_state block: backend = "gcs", bucket manabie-terraform-state-2 (default, per-env-overridable to e.g. manabie-staging-terraform-state), and a per-component prefix path_relative_to_include(). Because it's in the Terragrunt root, every leaf inherits it — each component (each env×org cell's GKE, apps, etc.) gets its own isolated state path in the shared bucket. So a mistake in one cell's state can't corrupt another's.

Locking & drift

Locking — no two applies at once If two people apply the same state simultaneously, they'd race and corrupt it. The GCS backend locks automatically — it takes a lock object before writing, so the second apply waits. (No separate lock database needed, unlike some AWS setups.) It's the reason Atlantis (Lesson 12) also locks state during a PR's plan/apply.
Drift — when reality wanders off Drift is when real infrastructure no longer matches state/config — usually because someone changed it in the console by hand.3 terraform plan detects it (it'll show a diff you didn't cause), and you reconcile by either applying the config back (revert the manual change) or importing reality into state. This is the IaC version of the "push-based drift" idea from Course 5 — infrastructure only matches code as of the last apply.
Read this next

Terraform — State, the GCS backend & drift

Why state exists, remote state + locking, and detecting/managing drift.

hashicorp — State · Backend: gcs
hashicorp — Manage resource drift

Check yourself (from memory)

Q1. Terraform state is…

State is the source of truth plan diffs against — config vs real infra vs state. Lose it and Terraform forgets what it owns.

Q2. Remote state (in GCS) is needed so that…

Shared backend + locking + versioning; a laptop-local state file doesn't work for a team or for Atlantis.

Q3. Drift is detected by…

A manual console change makes reality ≠ state; plan surfaces it. Reconcile via apply or import.
Terraform state — what, why remote, locking, drift.
recall, then click to reveal
STATE = Terraform's RECORD of the infra it manages — the SOURCE OF TRUTH plan diffs (config vs real infra vs state). Without it, every apply recreates everything. PRECIOUS: maps config→real IDs, can hold SECRETS; lose it → Terraform forgets what it owns. REMOTE STATE (backend = GCS here) → a team + Atlantis share one truth, versioned + encrypted; local tfstate doesn't scale. LOCKING: GCS backend locks AUTOMATICALLY (lock object) → no concurrent-apply corruption. DRIFT = reality ≠ state (a console click); plan detects it, reconcile via apply (revert) or import (adopt). REPO: root.hcl:11-23 gcs backend, bucket manabie-terraform-state-2, per-component prefix path_relative_to_include() = isolated state per cell/component.
Want to see how terraform import adopts existing infra, or why secrets in state argue for encrypting the bucket? Ask me.

1. Terraform — State.

2. Terraform — Backend: gcs.

3. Terraform — Manage resource drift.