← Back to Blog RSS

Terraform commands cheat sheet: from first init to state management

Terraform Infrastructure as Code State Management

Terraform has dozens of commands, but most engineers only need to understand a core set, and the ones that touch state deserve the most attention. This guide organises the essential Terraform commands by what they actually do, so readers can move faster and break less.

TL;DR
$ cat terraform-commands-cheat-sheet.tldr
• The core workflow runs through five commands every user needs: init, validate, fmt, plan, and apply – in that order for a reason.
• Some Terraform commands acquire a state lock when they run. Knowing which prevents concurrent operations from corrupting shared state in CI/CD pipelines and team environments.
• Maintain separate state files within the same configuration with workspace commands, just make sure you understand the trade-offs before you commit to them.
• The quick-reference table near the end maps every command in this guide to whether it reads or writes state, so you can scan it on the job.

Terraform's command line interface is broad. The full list of Terraform CLI commands runs longer than most people expect, and the official documentation covers all of them with roughly equal weight, which is not the same thing as equal importance.

In practice, most engineers use a small core set of commands, and the ones they know the least tend to be the ones that cause the most trouble.

The state file is where you most often find trouble. Knowing what a command does to your infrastructure is useful. Knowing what it does to your Terraform state file is what keeps you out of recovery mode at eleven at night.

A command that rewrites state incorrectly, or that runs without a lock while another process is mid-apply, can leave you with state that no longer reflects real infrastructure, and reconciling that gap does not make for a fun afternoon. In this guide, you'll find the essential Terraform commands organized by what they actually do to state, with enough context to use each one confidently.

The Terraform cheat sheet table further down this article covers every command mapped to whether it touches state and whether it acquires a lock.

Core workflow commands

According to Firefly's State of IaC Report, 73% of practitioners use Terraform.

That's a very large number of teams running the same sequence of Terraform CLI commands every day. The core workflow runs in a specific order:

$ terraform init
$ terraform validate
$ terraform fmt
$ terraform plan
$ terraform apply

terraform init is always first. It initializes the working directory, downloads the providers your Terraform configuration files reference, installs modules, and applies the backend settings that determine where your state will live.

Critically, it does not touch state itself, which means it is safe to run at any point without risk. The -upgrade flag is useful when you need to pull in newer provider versions without recreating your environment from scratch.

terraform validate checks that your configuration files are syntactically correct and internally consistent, catching syntax errors and references to resources or variables that do not exist, without ever connecting to a remote host or reading real infrastructure.

It lets you know if your Terraform code is structurally sound or not, and it belongs in every CI/CD pipeline before anything else runs.

terraform fmt formats your tf files to match the canonical Terraform style. The -recursive flag applies formatting to all Terraform configuration files in subdirectories, which is useful when you have larger codebases with nested modules. Code that is formatted correctly produces cleaner diffs and easier reviews, which means fewer misread changes over time.

terraform plan is where Terraform shows you what it intends to do before doing it.

It reads your Terraform configuration, compares the desired state expressed in your files against the current state of real infrastructure, and outputs the set of changes required to reach that desired state.

The -out flag saves the result to a plan file, which you can then pass to apply to ensure exactly what you reviewed is what gets executed. This flag is more important in CI/CD pipelines than in local development, but it is good practice regardless.

terraform apply executes the plan. Without a saved plan file, it runs a new plan and asks for confirmation before proceeding. The -auto-approve flag skips that confirmation, which is standard in automated pipelines but worth using carefully in interactive sessions.

Observation

Apply is the command that writes to state. Everything else in this section is preparation. Apply is the moment Terraform commits.

State commands

Most Terraform commands cheat sheets rush through this section, which is a mistake, because state commands are sometimes irreversible. The ones that look the most benign often carry the most risk.

terraform state list shows every resource instance tracked in the current state file. Nothing is modified. It is the right starting point when you need to understand what Terraform is managing before you start, and the command to reach for first when a plan has an unexpected output.

terraform state show takes a specific resource from that list and prints its attributes in full detail. Also read-only.

If you are debugging why a plan is proposing a change you did not expect, this command tells you exactly what Terraform currently believes about a given resource, which is usually the fastest path to understanding the discrepancy.

terraform state mv moves a resource from one address to another within the same state file, or between separate state files entirely. You can use it to rename resources or restructure modules without destroying and recreating the underlying cloud infrastructure.

It does write to state, and getting the source or destination address wrong produces a state that no longer matches reality.

terraform state rm removes a resource from state without destroying it in the cloud. The infrastructure continues to exist, but Terraform no longer manages it.

This command is useful when you want to hand a resource off to another configuration, or stop managing it with Terraform entirely, but it is also an easy way to introduce drift if you are not deliberate about why you are running it.

After you've removed a resource from state, you should also take it out of your configuration files, or the next plan will propose adding it back.

terraform state pull and terraform state push let you download the current state from your backend in JSON format, or upload a local state file to replace what is stored remotely. Pull is safe. Push is not. Uploading an incorrect state file with state push is one of the hardest mistakes to recover from, and should never be a first option.

Which Terraform commands lock state?

Terraform uses state locking to prevent concurrent runs from corrupting the state file. When a command acquires a lock, no other process can acquire one against that same state until the first operation finishes.

The Terraform commands that lock state are apply, destroy, plan, when you are writing a plan file with -out, and the state subcommands state mv, state rm, and state push. Read-only operations like state list, state show, and state pull do not acquire a lock.

In shared environments and CI/CD pipelines, lock contention is a real operational problem. If a process exits unexpectedly while holding a lock, the lock won't automatically be released.

terraform force-unlock removes a stuck lock using the lock ID, provided by the error message. Use it when you are certain no other process is actively running against the state in question. Otherwise, avoid using it, as running two concurrent applies against the same state is exactly what locking is designed to prevent. Check your pipeline, check running terminals, then decide.

Terraform workspace commands

Workspaces in the Terraform CLI can maintain multiple state files within the same Terraform configuration and the same backend. The current workspace name is exposed as a variable inside your configuration, letting you parameterize behavior across environments without duplicating code.

Each workspace maintains its own independent state, so a change applied in one workspace does not affect another, and state locking applies per workspace rather than globally across all workspaces in the backend.

terraform workspace list shows every workspace available in the current backend.

terraform workspace new creates a new workspace and switches to it immediately.

terraform workspace select switches to an existing workspace by name.

terraform workspace show prints the name of the current workspace, which is worth running before any destructive operation in a shared environment.

terraform workspace delete removes a workspace, though it will refuse to delete one that still contains state, which is a sensible guardrail.

Before committing to workspaces, bear in mind that they share the same backend configuration and the same root module. Teams managing environments that differ significantly in structure tend to find workspaces limiting and opt for separate configurations with separate state backends instead.

Select workspaces as the right tool when environments are structurally identical and differ only in variable values. When the underlying infrastructure starts to diverge between environments, the single shared module becomes a constraint rather than a convenience.

At scale, the manual coordination required to track which state files depend on which others, across many workspaces and separate backends, tends to become a real bottleneck. Terraform has no native mechanism for planning across state boundaries. To cope with this, teams either build orchestration tooling themselves or reach for something that already understands the relationships.

Utility and output commands

Engineers use these commands when inspecting or debugging infrastructure rather than changing it, but they're not all read-only.

terraform output prints the output values defined in your root module. It returns a specific value when it has that output name as an argument. With the -json flag, it returns all output values in JSON format, meaning you can pipe it into other tools or downstream CI/CD steps that depend on the values your configuration exposes.

terraform graph generates a visual representation of the dependency graph for your Terraform configuration in DOT format, which tools like Graphviz can render as a diagram.

Most engineers run it once out of curiosity and move on. The underlying dependency graph it exposes, the full set of relationships between every resource instance in your state and everything that depends on it, is actually the most important data structure in your entire infrastructure setup.

The fact that Terraform serializes it into a flat file and reconstructs it from scratch on every operation is a design choice.

terraform console opens an interactive shell for evaluating expressions against your current state and configuration files. It is useful when you are testing interpolations, trying to understand how Terraform resolves variable values, and checking that environment variables are being picked up as expected, without running a full plan.

terraform taint and terraform untaint are officially deprecated as of Terraform 0.15.2 and replaced by the -replace flag on plan and apply. You will still encounter them in older scripts and documentation, so it is still useful to know what they do. Taint marks a resource instance for recreation on the next apply, untaint reverses that. If you are on a current Terraform version, use terraform plan -replace=RESOURCE_ADDRESS instead.

terraform refresh updates the state file to match the current state of real infrastructure without making any changes to that infrastructure. Be aware that it writes to state, which surprises people who assume refresh is a read-only inspection command. Avoid running it in a configuration with significant drift, as that can overwrite state and cause confusion down the line.

Terraform commands cheat sheet

Every command covered in the Terraform commands list above is here, mapped to its main purpose, whether it touches state, and whether it acquires a state lock.

Command What it does Touches state Locks state
terraform init Initializes working directory, installs providers and modules, and applies backend settings No No
terraform validate Checks configuration files for syntax errors and internal consistency No No
terraform fmt Formats tf files to canonical style, while -recursive covers subdirectories No No
terraform plan Shows proposed changes without applying them, while -out saves a plan file Read only Only with -out
terraform apply Applies changes to real infrastructure, while -auto-approve skips confirmation Writes Yes
terraform destroy Destroys all infrastructure managed by the current configuration Writes Yes
terraform output Prints output values from current state, and -json returns JSON format Read only No
terraform refresh Updates state to reflect current real infrastructure Writes No
terraform console Opens interactive shell for evaluating expressions against current state Read only No
terraform graph Outputs the dependency graph in DOT format No No
terraform version Prints the installed Terraform version No No
terraform state list Lists all resource instances tracked in the state file Read only No
terraform state show Shows full attributes of a specific resource instance Read only No
terraform state mv Moves a resource to a new address within or between state files Writes Yes
terraform state rm Removes a resource from state without destroying it in the cloud Writes Yes
terraform state pull Downloads current remote state as JSON Read only No
terraform state push Uploads a local state file to the remote backend Writes Yes
terraform force-unlock Removes a stuck state lock by ID No Removes lock
terraform workspace list Lists all workspaces in the current backend No No
terraform workspace new Creates and switches to a new workspace No No
terraform workspace select Switches to an existing workspace No No
terraform workspace show Prints the current workspace name No No
terraform workspace delete Deletes a workspace, refusing if state exists No No
terraform taint (deprecated) Marks a resource instance for recreation, but now you can use -replace instead Writes Yes
terraform untaint (deprecated) Removes taint from a resource instance Writes Yes

The commands most likely to cause real damage

Make sure you are especially cautious when you use these commands.

terraform destroy removes all infrastructure resources managed by the current configuration. It is the best command when you want to tear down an environment that is no longer needed. But it is not a command you should run without first confirming which workspace you are in, what state that workspace contains, and whether anyone else is currently operating against it.

The destroy command acquires a lock, runs a plan in reverse, and asks for confirmation before proceeding, but it will proceed if you confirm, regardless of the scale of the consequences.

terraform force-unlock should only be used when you are genuinely certain no process is actively running against the state in question. The state lock exists to prevent concurrent writes. Removing it while a process is mid-apply does not stop that process, it only removes the mechanism that would prevent a second process from starting alongside it.

Confirm your CI/CD pipeline is not mid-run and that no terminal session is holding a lock, and only then reach for force-unlock.

terraform state rm is not potentially destructive to infrastructure itself, but can affect Terraform's awareness of it. A resource removed from state is a resource Terraform will offer to create on the next plan, because it no longer exists from Terraform's perspective.

If you use it to stop managing a resource, it needs to come out of your configuration files at the same time, or the next run will propose adding it right back.

State awareness is the real skill

An understanding of what each Terraform command does to state is what separates a practitioner who debugs quickly from one who spends hours in recovery.

You can learn the commands in an afternoon, but having full awareness of the state takes longer, and only comes from understanding the full picture of what Terraform is actually managing and how the pieces relate to each other.

For teams who want that picture made explicit, including blast radius analysis across state files, dependency graphs that reflect what actually deployed, and cross-state transactions that surface the full impact of a change before it lands, Stategraph is built for exactly that. Read our docs for more information.

You can also start a free trial to get to grips with the tool.