Most tools that build infrastructure run steps. This one keeps a map. You describe the end state you want; it compares that against a file recording which real object each block already stands for, and proposes the difference. Almost everything that surprises people — a plan that wants to destroy something you merely renamed, a change nobody made, a run that silently waits on another — comes from that map rather than the language. So the language is the short part of this guide and the map is the long part: learn what state holds, when it is read, and who may write it.
Each chapter opens with the short version. Tap one to read the detail.
The model, its plugins, and its one escape hatch
~2 min
You describe the end state; the tool derives the steps, which is why running the same configuration twice proposes nothing the second time. The work is done by provider plugins you pin like any dependency, and by provisioners, which sit outside the model.
State: the map from your configuration to real things
~2 min
State binds each resource block to the object it actually created — how the tool knows which server aws_instance.web means. It is plain text, secrets included: marking a value sensitive hides it from output, not from the file.
A plan is a diff against state, refreshed
~2 min
Planning is three steps: read the existing remote objects to bring state up to date, compare configuration against that state, propose actions. The trap is believing it diffs against reality — switch the refresh off and you diff a map that may be weeks stale.
The order you never wrote down
~2 min
Nothing runs in file order. References between resources become edges in a graph, which is validated to have no cycles and walked in parallel as soon as each node's dependencies finish. An ordering you assumed but never expressed does not exist.
Four things that can happen to a resource
~2 min
Every planned change is one of four actions: create, destroy, update in place, or destroy and re-create. Which one you get is decided by the remote platform's limits, not by how small your edit looked — and deleting a block means destroy.
count and for_each are two addressing schemes
~2 min
count addresses instances by position — [0], [1] — while for_each addresses them by map key or set member. Because state binds real objects to those addresses, the choice decides what happens when a middle item disappears.
Changing the map without touching the territory
~2 min
A resource's address is its key in state, so renaming a block reads as "destroy the old, create a new". The moved, removed and import blocks re-point the map without touching real infrastructure — and unlike the state subcommands, they produce a reviewable plan.
Shared state, and the lock that makes it safe
~2 min
The default backend writes state to a local file, which fails the moment a second person or pipeline runs. A remote backend fixes sharing; locking fixes concurrency. Workspaces give one configuration several states, but are not environment isolation.
A module is a directory with a contract
~2 min
A module is just a directory of configuration; what makes it reusable is its contract — variables in, outputs out, nothing else visible. Locals are private, and a module meant to be called by others must not configure its own providers.
The language in one pass
~2 min
Configuration is blocks and arguments, and file order never matters. Two things carry most of the confusion: null means "as if omitted" rather than empty, and a value the platform has not produced yet is *unknown*, which spreads silently through every expression touching it.
Four kinds of check, and what each one can catch
~2 min
Validation, custom conditions, check blocks and terraform test fail at different moments and with different force. Two surprise people: a failed check is only a warning, and terraform test provisions real infrastructure unless told otherwise.
Written by Keentune. We are not affiliated with or endorsed by the organizations whose documentation informs this guide, and any linked sources belong to their respective owners.
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.