TERRAFORM Updated 2026-07-08 102+ commands Verified against official docs

Terraform Cheat Sheet

100+ Terraform commands for init, plan, apply, state, workspaces, import, and more. Includes an Error Message Lookup section. Verified against official HashiCorp docs.

Ctrl+K

Everything runs in your browser. No commands or data are sent to any server.

Paste the error you are seeing and find the command that fixes it. These are the most searched Terraform errors on Stack Overflow with combined views in the millions.

Error acquiring the state lock: ConditionalCheckFailedException

What it means

Another Terraform process is holding the state lock in DynamoDB. This happens when a previous run crashed or was interrupted without releasing the lock.

Fix

terraform force-unlock <LOCK_ID>

Gotcha

Get the LOCK_ID from the error message output. Only run this if you are certain no other legitimate Terraform process is running. Check your DynamoDB lock table first.

Error: Provider configuration not present

What it means

Your state file references a provider that is no longer configured in your current Terraform files. Usually happens after reorganizing code or moving resources between modules.

Fix

terraform init -upgrade

Gotcha

If init does not fix it you may need to remove the orphaned provider from state with terraform state rm.

Error: Required plugins are not installed

What it means

The .terraform.lock.hcl file exists but the actual provider binaries are missing from .terraform/providers. Common after cloning a repo or cleaning the directory.

Fix

terraform init

Gotcha

Always run terraform init after cloning a repo or after any change to required_providers blocks.

Error: Conflicting configuration arguments

What it means

Two arguments in the same resource block are mutually exclusive. Common with security group rules that have both inline rules and separate rule resources.

Fix

terraform validate

Gotcha

Run terraform validate to get the exact line and argument names. Remove one of the conflicting arguments from the resource block.

No changes. Your infrastructure matches the configuration.

What it means

This is not an error. Terraform found the real infrastructure matches what is in your .tf files exactly. Nothing needs to be applied.

Fix

terraform show

Gotcha

Run terraform show to see the current state of all managed resources. If you expected changes, check that you saved your .tf files before running plan.

Error: Resource not found in state

What it means

You are targeting a resource with -target or trying to import into a resource address that does not exist in your current state.

Fix

terraform state list

Gotcha

Run terraform state list to see all resource addresses in state. Copy the exact address including module path if the resource is inside a module.

New to Terraform? Start with these

5 essential commands to get you started. The full reference is right below.

Initialize a working directory

terraform init

Run this first in any new Terraform directory, after cloning a repo, or after adding a new provider.

Validate configuration syntax

terraform validate

Check your configuration for syntax errors and basic logic problems before running plan.

Format configuration files

terraform fmt

Format all .tf files in the current directory to the canonical Terraform style.

Preview infrastructure changes

terraform plan

Preview every change Terraform will make before making any of them.

Apply infrastructure changes

terraform apply

Apply the changes shown in the last plan to your real infrastructure.

102 commands

Initialize a working directory

Beginner
terraform init

↓ Click command to explain

-upgrade Upgrades all providers to the latest version allowed by version constraints
-reconfigure Reinitializes the backend, ignoring any existing configuration
-backend=false Skips backend initialization

When to use this

Run this first in any new Terraform directory, after cloning a repo, or after adding a new provider.

Gotcha

Always run terraform init after any change to required_providers or backend blocks. The most common cause of confusing errors is forgetting this step.

Validate configuration syntax

Beginner
terraform validate

↓ Click command to explain

-json Outputs validation results as JSON for use in CI pipelines

When to use this

Check your configuration for syntax errors and basic logic problems before running plan.

Gotcha

Validate only checks syntax and basic logic. It does not check whether your AWS resources actually exist or whether your IAM permissions allow the actions you are requesting.

Format configuration files

Beginner
terraform fmt

↓ Click command to explain

-recursive Formats all .tf files in subdirectories as well
-check Exits with a non-zero status if files are not formatted, without changing them (use in CI)
-diff Shows the diff of what would change

When to use this

Format all .tf files in the current directory to the canonical Terraform style.

Gotcha

Run terraform fmt before every commit. Many teams enforce this in CI with terraform fmt -check and fail the pipeline if files are not formatted.

Preview infrastructure changes

Beginner
terraform plan

↓ Click command to explain

-out=tfplan Saves the plan to a file so apply can use the exact same plan
-target=resource_type.name Limits the plan to one specific resource
-var-file=vars.tfvars Loads variable values from a file
-destroy Shows what terraform destroy would do

When to use this

Preview every change Terraform will make before making any of them.

Gotcha

Always save the plan with -out=tfplan in CI pipelines so the apply step uses the exact plan that was reviewed. Without -out, a new plan is generated at apply time which may differ from what was reviewed.

Apply infrastructure changes

Beginner Destructive
terraform apply

↓ Click command to explain

-auto-approve Skips the confirmation prompt (use in CI only)
tfplan Applies a previously saved plan file passed as an argument
-target=resource_type.name Applies only one specific resource

When to use this

Apply the changes shown in the last plan to your real infrastructure.

Gotcha

Never use -auto-approve in manual workflows. Only use it in CI pipelines where the plan has already been reviewed and approved by a human.

Destroy all managed infrastructure

Intermediate Destructive
terraform destroy

↓ Click command to explain

-auto-approve Skips the confirmation prompt
-target=resource_type.name Destroys only one resource

When to use this

Destroy all resources managed by the current Terraform configuration.

Gotcha

This permanently deletes real infrastructure and there is no undo. Always run terraform plan -destroy first to see exactly what will be deleted.

Preview a destroy operation

Intermediate
terraform plan -destroy

↓ Click command to explain

When to use this

Preview exactly what terraform destroy would delete before actually deleting anything.

Read output values

Beginner
terraform output

↓ Click command to explain

-json Outputs all values as JSON for use in scripts
-raw Outputs a single value as a plain string with no quotes (use in shell scripts)
output_name Shows only that specific output value

When to use this

Read the output values from a completed apply, such as a load balancer URL or database endpoint.

Gotcha

Outputs are only available after a successful apply. If you just ran init or plan, there are no outputs yet.

Show the current state in human-readable form

Beginner
terraform show

↓ Click command to explain

-json Outputs state as JSON for use in scripts
tfplan Shows what a saved plan file would do

When to use this

Display the current state of all managed resources in a human readable format.

Sync state with real infrastructure

Advanced Destructive
terraform refresh

↓ Click command to explain

When to use this

Sync the Terraform state file with the real state of your infrastructure without making any changes.

Gotcha

terraform refresh is deprecated as a standalone command in recent Terraform versions. Use terraform apply -refresh-only instead, which shows you what would change in state before committing.

Update state without changing infrastructure

Intermediate
terraform apply -refresh-only

↓ Click command to explain

When to use this

Update the state file to match the real infrastructure without making any infrastructure changes.

Generate a resource dependency graph

Advanced
terraform graph | dot -Tsvg > graph.svg

↓ Click command to explain

When to use this

Generate a visual dependency graph of all resources showing which resources depend on which others.

Gotcha

Requires graphviz to be installed locally. The output is dot format and must be piped to a renderer.

Check the installed Terraform version

Beginner
terraform version

↓ Click command to explain

When to use this

Check which version of Terraform is installed and which providers are being used.

Get plan output as machine-readable JSON

Advanced
terraform plan -json

↓ Click command to explain

When to use this

Stream the plan as structured JSON for tooling that renders or analyzes plan output, such as CI dashboards or policy checks.

Gotcha

The JSON stream is a series of newline-delimited JSON objects, not a single JSON document, so it needs a streaming parser rather than a plain JSON.parse.

Get apply output as machine-readable JSON

Advanced Destructive
terraform apply -json

↓ Click command to explain

When to use this

Stream apply progress as structured JSON, useful for building a custom deployment UI or parsing results in CI.

Check version information as JSON

Intermediate
terraform version -json

↓ Click command to explain

When to use this

Read the Terraform and provider versions programmatically in a script instead of parsing plain text output.

Apply without interactive prompts

Intermediate Destructive
terraform apply -input=false

↓ Click command to explain

When to use this

Run apply in a non-interactive environment such as CI, where there is no terminal available to answer a variable prompt.

Gotcha

If a required variable has no default and no value is supplied, -input=false makes apply fail immediately with a clear error instead of hanging while it waits for input that will never come.

Plan without interactive prompts

Intermediate
terraform plan -input=false

↓ Click command to explain

When to use this

Run plan in CI where no terminal is available to answer a missing variable prompt.

Read outputs without ANSI color codes

Beginner
terraform output -no-color

↓ Click command to explain

When to use this

Print output values without terminal color codes so the result is clean when piped into a log file or another tool.

List all resources in state

Beginner
terraform state list

↓ Click command to explain

-state=path Uses a specific state file instead of the default

When to use this

List every resource currently tracked in the Terraform state file.

Gotcha

If you get an error about a resource not existing, run this first to see the exact address including module path.

Show a resource's full attributes

Intermediate
terraform state show resource_type.name

↓ Click command to explain

When to use this

Show the full attributes of one specific resource as stored in state.

Gotcha

The resource address must match exactly, including module path. Use terraform state list first to find the correct address.

Rename or move a resource in state

Advanced Destructive
terraform state mv resource_type.old_name resource_type.new_name

↓ Click command to explain

When to use this

Rename a resource in state without destroying and recreating it, or move a resource into or out of a module.

Gotcha

Always run terraform plan after a state mv to confirm Terraform sees the resource correctly in its new location before running apply.

Stop tracking a resource in state

Advanced Destructive
terraform state rm resource_type.name

↓ Click command to explain

When to use this

Remove a resource from state without destroying the real infrastructure, useful when you want Terraform to stop managing a resource.

Gotcha

The real infrastructure is not deleted when you remove it from state. Terraform simply stops tracking it, but the next terraform plan will try to create it again unless you also remove it from your .tf files.

Download the current remote state

Intermediate
terraform state pull

↓ Click command to explain

When to use this

Download and print the current remote state as JSON, useful for inspecting or backing up state.

Upload a local state file to the backend

Advanced Destructive
terraform state push terraform.tfstate

↓ Click command to explain

When to use this

Upload a local state file to the remote backend, used for disaster recovery.

Gotcha

Pushing an incorrect state file can corrupt your infrastructure tracking. Always back up the current remote state with terraform state pull before pushing.

Release a stuck state lock

Advanced Destructive
terraform force-unlock LOCK_ID

↓ Click command to explain

When to use this

Release a stuck state lock when a previous Terraform run crashed and left the lock in DynamoDB.

Gotcha

Only run this if you are absolutely certain no other Terraform process is legitimately holding the lock. Check your DynamoDB lock table first and confirm no other pipeline is running.

Update state to a new provider source

Advanced Destructive
terraform state replace-provider old_provider new_provider

↓ Click command to explain

When to use this

Update state to reference a renamed or moved provider without destroying resources.

Mark a resource for forced recreation

Advanced Destructive
terraform taint resource_type.name

↓ Click command to explain

When to use this

Mark a resource as tainted so the next apply destroys and recreates it, useful when a resource is broken in a way Terraform cannot detect.

Gotcha

Tainting a resource does not change anything immediately. It only affects the next plan or apply, and in modern Terraform the -replace flag on apply is the recommended alternative since it does not require a separate command run first.

Remove a taint mark from a resource

Intermediate
terraform untaint resource_type.name

↓ Click command to explain

When to use this

Undo a taint mark on a resource so the next apply leaves it alone instead of recreating it.

Force a specific resource to be recreated

Advanced Destructive
terraform apply -replace=resource_type.name

↓ Click command to explain

When to use this

Force Terraform to destroy and recreate a single resource in one step, the modern replacement for the separate taint command.

Gotcha

This still runs a full plan and apply, so review the plan output before confirming since -replace can be combined with other pending changes in the same apply.

Plan without refreshing state first

Advanced
terraform plan -refresh=false

↓ Click command to explain

When to use this

Skip the state refresh step before planning, which speeds up plans significantly in large configurations with many resources.

Gotcha

The plan may miss drift that happened outside Terraform since the last refresh, so only use this for speed in situations where you already trust the current state.

Apply without acquiring a state lock

Advanced Destructive
terraform apply -lock=false

↓ Click command to explain

When to use this

Disable state locking during apply, used when the configured backend does not support locking or to work around a stuck lock in an emergency.

Gotcha

Disabling locking removes the safety net that prevents two people from applying at the same time, which can corrupt state if anyone else is running Terraform concurrently.

Wait longer for a state lock

Advanced Destructive
terraform apply -lock-timeout=5m

↓ Click command to explain

When to use this

Wait up to the given duration for the state lock to become available instead of failing immediately, useful when a previous run is still finishing.

Refresh state for a single resource

Advanced
terraform apply -refresh-only -target=resource_type.name

↓ Click command to explain

When to use this

Update state for one specific resource to match reality without touching the rest of the infrastructure or state.

Find a resource by its real cloud ID

Advanced
terraform state list -id=i-1234567890abcdef0

↓ Click command to explain

When to use this

Find which Terraform resource address corresponds to a real cloud resource ID found in a console alert or another team's report.

Remove an entire module from state

Advanced Destructive
terraform state rm module.mymodule

↓ Click command to explain

When to use this

Remove every resource inside a module from state at once, such as when deleting a module block but wanting to keep the underlying infrastructure untouched.

Gotcha

This stops Terraform from tracking every resource the module created, so make sure the plan afterward does not try to recreate them because the module block is still present in your configuration.

Destroy one specific resource

Advanced Destructive
terraform destroy -target=resource_type.name

↓ Click command to explain

When to use this

Destroy a single resource without touching the rest of the infrastructure managed by the same configuration.

Gotcha

-target is meant for exceptional situations, not routine use. Repeatedly targeting individual resources instead of applying the full configuration can let real infrastructure drift away from what your .tf files describe.

Move a resource into a separate state file

Advanced Destructive
terraform state mv -state-out=new.tfstate resource_type.name resource_type.name

↓ Click command to explain

When to use this

Move a resource out of the current state into a different state file entirely, such as when splitting one large configuration into several smaller ones.

Back up remote state to a local file

Intermediate
terraform state pull > backup.tfstate

↓ Click command to explain

When to use this

Create a manual local backup of the current remote state before running a risky operation like state rm, state mv, or force-unlock.

Gotcha

Get in the habit of running this before any command that rewrites state directly, since it gives you something to restore from with terraform state push if something goes wrong.

Plan without acquiring a state lock

Advanced
terraform plan -lock=false

↓ Click command to explain

When to use this

Skip acquiring the state lock during plan, useful when a backend does not support locking or when read-only inspection is needed while a lock is held elsewhere.

Inspect a resource inside a module

Intermediate
terraform state show 'module.mymodule.resource_type.name'

↓ Click command to explain

When to use this

Show the attributes of a resource that lives inside a module rather than at the root of the configuration.

Gotcha

The quotes around the module address are required in most shells because the dots and brackets in a nested module path can otherwise be misinterpreted by the shell.

Apply several specific resources at once

Advanced Destructive
terraform apply -target=resource_type.name1 -target=resource_type.name2

↓ Click command to explain

When to use this

Apply changes to more than one specific resource by repeating the -target flag, without applying the rest of the configuration.

Inspect a local backup state file

Intermediate
terraform state list -state=terraform.tfstate.backup

↓ Click command to explain

When to use this

List resources from a specific local state file, such as the automatic .tfstate.backup Terraform writes before overwriting state, instead of the active remote state.

Force push a state file, bypassing safety checks

Advanced Destructive
terraform state push -force terraform.tfstate

↓ Click command to explain

When to use this

Override the remote state's serial and lineage checks when pushing, used only when recovering from a corrupted or intentionally divergent local state.

Gotcha

This bypasses the exact safety check that normally prevents you from accidentally overwriting newer state with an older copy, so confirm you actually have the most current state before using -force.

Refresh state for one resource (legacy syntax)

Advanced Destructive
terraform refresh -target=resource_type.name

↓ Click command to explain

When to use this

Sync state for a single resource using the older refresh command, seen in scripts written before apply -refresh-only existed.

Gotcha

Prefer terraform apply -refresh-only -target=resource_type.name in current Terraform versions, since standalone refresh is deprecated and offers no preview of what will change before committing it.

List all workspaces

Beginner
terraform workspace list

↓ Click command to explain

When to use this

List all workspaces. The current one is marked with an asterisk.

Create a new workspace

Intermediate Destructive
terraform workspace new staging

↓ Click command to explain

When to use this

Create a new workspace to manage a separate state for the same configuration, for example dev, staging, and production.

Gotcha

Creating a new workspace does not copy any existing resources. Each workspace has a completely separate state file.

Switch to a different workspace

Beginner
terraform workspace select production

↓ Click command to explain

When to use this

Switch to a different workspace before running plan or apply.

Gotcha

Always check which workspace is active with terraform workspace show before running any destructive commands. Running terraform destroy in production when you thought you were in dev is catastrophic.

Show the current workspace

Beginner
terraform workspace show

↓ Click command to explain

When to use this

Print the name of the currently active workspace.

Gotcha

Run this before any destructive operation to confirm you are in the right workspace.

Delete a workspace

Advanced Destructive
terraform workspace delete staging

↓ Click command to explain

When to use this

Delete a workspace after you have destroyed all its resources.

Gotcha

You must destroy all resources in a workspace before deleting it, and you cannot delete the default workspace.

Create a workspace seeded from an existing state file

Advanced Destructive
terraform workspace new -state=path/to/existing.tfstate staging

↓ Click command to explain

When to use this

Create a new workspace pre-populated from an existing state file instead of starting empty, useful when converting a single-workspace setup into multiple workspaces.

Select a workspace, creating it if needed

Intermediate Destructive
terraform workspace select -or-create=staging

↓ Click command to explain

When to use this

Switch to a workspace in a single command, automatically creating it first if it does not already exist, which avoids a separate new step in CI pipelines.

Import an existing resource into state

Advanced Destructive
terraform import resource_type.name resource_id

↓ Click command to explain

When to use this

Import an existing real infrastructure resource into Terraform state so Terraform can start managing it.

Gotcha

Importing a resource only updates state. It does not write the corresponding .tf configuration for you. Write the resource block in your .tf files manually before importing, and make sure the configuration matches the real resource or the next plan will show changes.

Generate configuration for imported resources

Advanced
terraform plan -generate-config-out=generated.tf

↓ Click command to explain

When to use this

Automatically generate the .tf configuration for resources being imported, available in Terraform 1.5 and later.

Gotcha

Generated configuration is a starting point, not a finished product. Always review and clean up the generated .tf file before committing it.

Generate the provider dependency lock file

Intermediate
terraform providers lock

↓ Click command to explain

-platform=linux_amd64 Locks for a specific platform

When to use this

Generate or update the .terraform.lock.hcl file to pin provider versions for reproducible builds.

Gotcha

The .terraform.lock.hcl file should be committed to git. This was one of the most upvoted Terraform Stack Overflow questions.

Download providers for offline use

Advanced
terraform providers mirror /path/to/mirror

↓ Click command to explain

When to use this

Download all required providers to a local directory for use in air-gapped or offline environments.

Import a resource that needs variable values

Advanced Destructive
terraform import -var="region=us-east-1" aws_instance.example i-1234567890abcdef0

↓ Click command to explain

When to use this

Import a resource whose configuration references a variable, so Terraform can evaluate the resource address correctly during the import.

Import a resource into a module address

Advanced Destructive
terraform import 'module.mymodule.aws_instance.example' i-1234567890abcdef0

↓ Click command to explain

When to use this

Import an existing resource directly into a nested module address instead of the root module.

Gotcha

The quotes around the module address are required in most shells, since the dots in a nested module path can otherwise be misinterpreted.

Mirror providers for a specific platform

Advanced
terraform providers mirror -platform=linux_amd64 /path/to/mirror

↓ Click command to explain

When to use this

Download only the provider binaries needed for a specific operating system and architecture, useful when preparing a mirror for a Linux CI runner from a different machine.

Generate configuration for one imported resource

Advanced
terraform plan -generate-config-out=generated.tf -target=aws_instance.example

↓ Click command to explain

When to use this

Generate configuration for a single resource being imported instead of every resource pending import at once.

Open an interactive expression console

Intermediate
terraform console

↓ Click command to explain

When to use this

Open an interactive console to evaluate Terraform expressions, test functions, and inspect values before using them in configuration.

Gotcha

Type exit or press Ctrl-D to quit. This is the fastest way to test a complex expression before putting it in your code.

Get all outputs as JSON

Intermediate
terraform output -json

↓ Click command to explain

When to use this

Get all output values as JSON for use in scripts or to pass values to another tool.

Pass a single variable value on the command line

Intermediate
terraform plan -var="environment=staging"

↓ Click command to explain

When to use this

Pass a single variable value on the command line for a quick test without editing a .tfvars file.

Gotcha

For multiple variables, use a .tfvars file with -var-file instead of multiple -var flags.

Apply with variables from a specific file

Intermediate Destructive
terraform apply -var-file="production.tfvars"

↓ Click command to explain

When to use this

Apply using variable values from a specific .tfvars file, such as production.tfvars.

Gotcha

Never commit .tfvars files containing secrets to git. Use environment variables or a secrets manager for sensitive values.

Inspect specific resource attributes with jq

Advanced
terraform show -json | jq '.values.root_module.resources'

↓ Click command to explain

When to use this

Pipe the structured state output into jq to extract exactly the resource attributes you need, without scrolling through the full human-readable show output.

Read a single output as a raw shell value

Intermediate
terraform output -raw db_password

↓ Click command to explain

When to use this

Read a single named output value with no surrounding quotes, ready to pipe directly into another command or store in a shell variable.

Gotcha

Terraform still prints sensitive outputs in plain text with -raw. Be careful about where the output ends up, such as shell history or CI logs.

Preview a plan for a specific environment

Intermediate
terraform plan -var-file="staging.tfvars"

↓ Click command to explain

When to use this

Preview the changes for a specific environment's variable values before applying, such as checking staging.tfvars separately from production.tfvars.

Evaluate a single expression non-interactively

Advanced
echo 'aws_instance.example.id' | terraform console

↓ Click command to explain

When to use this

Pipe a single expression into terraform console from a script to evaluate one value without opening an interactive session.

Pass multiple variables on the command line

Intermediate
terraform plan -var="region=us-east-1" -var="environment=staging"

↓ Click command to explain

When to use this

Pass several individual variable values by repeating the -var flag, useful for a quick test with more than one override.

Download referenced modules

Intermediate
terraform get

↓ Click command to explain

-update Downloads the latest version of modules within version constraints

When to use this

Download and install all modules referenced in your configuration without reinitializing the backend.

Gotcha

terraform init also runs terraform get. Use terraform get -update specifically when you want to update modules without touching the backend configuration.

Show provider requirements

Beginner
terraform providers

↓ Click command to explain

When to use this

Show the provider requirements for the current configuration and which module requires each provider.

Upgrade providers and modules

Intermediate
terraform init -upgrade

↓ Click command to explain

When to use this

Upgrade all providers and modules to the latest versions allowed by your version constraints.

Gotcha

This updates the .terraform.lock.hcl file. Commit the updated lock file to git so teammates use the same provider versions.

Initialize a directory with OpenTofu

Intermediate
tofu init

↓ Click command to explain

When to use this

OpenTofu is an open source fork of Terraform with an Apache 2.0 license. Its CLI commands are identical to Terraform but use the tofu binary instead of terraform.

Gotcha

If your team is migrating from Terraform to OpenTofu for license reasons, every command in this cheat sheet works identically with tofu replacing terraform in the command.

Dump the full provider schema

Advanced
terraform providers schema -json

↓ Click command to explain

When to use this

Dump every resource and data source argument for every provider in the configuration as JSON, useful for tooling, documentation generation, or checking exactly what a resource type accepts.

Install providers from a local directory

Advanced
terraform init -plugin-dir=/path/to/local/providers

↓ Click command to explain

When to use this

Initialize using providers from a local directory instead of the registry, used in air-gapped environments alongside terraform providers mirror.

Gotcha

When -plugin-dir is set, Terraform stops checking the registry entirely and dependency lock file verification is skipped, so make sure the directory actually has every provider version you need.

Lock providers for every platform your team uses

Advanced
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 -platform=windows_amd64

↓ Click command to explain

When to use this

Lock provider checksums for multiple operating systems and architectures at once, since developers on macOS and CI running on Linux both need matching entries in the lock file.

Gotcha

Running terraform providers lock with no -platform flag only adds entries for the platform you ran it on, which is why teams with mixed development machines and CI runners need to repeat the flag for each platform.

Update modules to their latest allowed version

Intermediate
terraform get -update

↓ Click command to explain

When to use this

Re-download every referenced module at the newest version allowed by its version constraint, without touching provider or backend configuration.

Pass backend configuration on the command line

Advanced
terraform init -backend-config="bucket=my-tf-state" -backend-config="key=prod/terraform.tfstate"

↓ Click command to explain

When to use this

Provide backend configuration values on the command line instead of hardcoding them in the backend block, useful for keeping secrets out of .tf files.

Migrate state to a new backend

Advanced Destructive
terraform init -migrate-state

↓ Click command to explain

When to use this

Migrate existing state to a new backend when you are changing backend configuration.

Gotcha

Always back up your current state file before migrating backends. This copies state to the new location, but if anything goes wrong you need the backup.

Reinitialize the backend from scratch

Advanced
terraform init -reconfigure

↓ Click command to explain

When to use this

Reinitialize the backend, ignoring any existing backend configuration, used when switching between backends.

Initialize without interactive prompts

Intermediate
terraform init -input=false

↓ Click command to explain

When to use this

Disable interactive prompts for backend configuration values, required in CI pipelines since there is no terminal to answer them.

Gotcha

Without -input=false, a CI job with a partially configured backend can appear to hang forever while it silently waits for input that will never arrive.

Initialize without downloading modules

Advanced
terraform init -get=false

↓ Click command to explain

When to use this

Skip downloading modules during init, useful when only reconfiguring the backend and modules are already present.

Initialize without configuring a backend

Intermediate
terraform init -backend=false

↓ Click command to explain

When to use this

Skip backend initialization entirely, useful when only working with modules locally or testing configuration without connecting to remote state.

Gotcha

Running plan or apply after -backend=false still fails, since those commands need a working backend. Use this only for quick local checks like validate or fmt.

Migrate backends without a confirmation prompt

Advanced Destructive
terraform init -force-copy

↓ Click command to explain

When to use this

Skip the interactive yes or no prompt that normally appears when copying state to a new backend, useful for scripted backend migrations in CI.

Gotcha

This skips a safety confirmation, so only use it in a scripted migration you have already tested manually once.

Switch backends and upgrade providers together

Advanced
terraform init -reconfigure -upgrade

↓ Click command to explain

When to use this

Reconfigure the backend and upgrade providers to the latest allowed versions in a single init call, common when switching backends and bumping provider versions at the same time.

Wait longer for the backend lock during init

Advanced
terraform init -lock-timeout=5m

↓ Click command to explain

When to use this

Wait up to the given duration for the backend's state lock during init instead of failing immediately, useful when init runs right after another pipeline stage that briefly holds the lock.

Enable verbose debug logging

Advanced
TF_LOG=DEBUG terraform plan

↓ Click command to explain

When to use this

Enable verbose debug logging to diagnose provider errors, API call failures, or unexpected behavior.

Gotcha

The output is extremely verbose. Pipe it to a file with TF_LOG=DEBUG terraform plan 2> debug.log and search for the specific error rather than reading the whole output.

Write debug logs to a file

Advanced
export TF_LOG=DEBUG && export TF_LOG_PATH=./terraform.log && terraform plan

↓ Click command to explain

When to use this

Write debug logs to a file instead of printing them to the terminal.

Validate and output results as JSON

Intermediate
terraform validate -json

↓ Click command to explain

When to use this

Validate configuration and output results as JSON for parsing in CI pipelines.

Get a distinct exit code for pending changes

Advanced
terraform plan -detailed-exitcode

↓ Click command to explain

When to use this

Exit with code 0 if there are no changes, 1 if there is an error, and 2 if there are changes, useful in CI to distinguish success with no changes from success with pending changes.

Gotcha

Without -detailed-exitcode, terraform plan exits with 0 whether or not there are changes, so CI cannot tell the difference between a plan that succeeded with nothing to do and one that succeeded with changes waiting to be applied.

Limit concurrent operations

Advanced Destructive
terraform apply -parallelism=5

↓ Click command to explain

When to use this

Limit the number of concurrent operations Terraform performs, the default is 10, useful for rate-limited APIs.

Gotcha

Reducing parallelism slows down applies but can prevent API throttling errors from cloud providers.

Enable the most verbose logging level

Advanced Destructive
TF_LOG=TRACE terraform apply

↓ Click command to explain

When to use this

Enable trace level logging, one level more detailed than DEBUG, used when debug logs are not detailed enough to diagnose a provider crash.

Collapse repeated warnings into a summary

Intermediate
terraform plan -compact-warnings

↓ Click command to explain

When to use this

Collapse repeated warning messages into a single summary line, useful for large configurations where warnings would otherwise flood CI output.

Validate without ANSI color codes

Intermediate
terraform validate -no-color

↓ Click command to explain

When to use this

Disable ANSI color codes in validate output, needed when piping output into a log file or a CI system that does not render terminal colors.

Gotcha

Without -no-color, logs captured by some CI systems show raw escape codes mixed into the text instead of clean output.

Scope debug logging to provider communication

Advanced
TF_LOG_PROVIDER=DEBUG terraform plan

↓ Click command to explain

When to use this

Scope debug logging to only the communication between Terraform and provider plugins, producing a smaller and more focused log when the bug is clearly inside a provider.

Scope debug logging to Terraform core

Advanced
TF_LOG_CORE=DEBUG terraform plan

↓ Click command to explain

When to use this

Scope debug logging to only Terraform core internals, excluding provider chatter, useful when the bug is in Terraform itself rather than a provider.

Run a safe CI apply step

Advanced Destructive
terraform apply -auto-approve -input=false

↓ Click command to explain

When to use this

Combine auto approval with disabled input prompts, the standard safe pairing for a CI pipeline apply step since a missing variable fails loudly instead of hanging.

Gotcha

Only use -auto-approve in a pipeline where the plan has already been reviewed as a separate step. Never combine it with a plan that has not been seen by a human.

Check a state command's exit code in a script

Intermediate
terraform state list > /dev/null; echo $?

↓ Click command to explain

When to use this

Check whether a state command succeeded from within a script by testing its exit code, without needing to parse the actual output.

Combine detailed exit codes with clean CI output

Advanced
terraform plan -detailed-exitcode -no-color

↓ Click command to explain

When to use this

Combine a parseable exit code with disabled color output, the standard combination for CI systems that need both a reliable exit code and clean log text.

Isolate the local Terraform working directory

Advanced
TF_DATA_DIR=/tmp/terraform-cache terraform init

↓ Click command to explain

When to use this

Override where Terraform stores its local .terraform working directory, used to isolate concurrent Terraform runs in the same CI workspace so parallel jobs do not overwrite each other's provider cache.

Inject default flags into every plan

Advanced
TF_CLI_ARGS_plan="-no-color" terraform plan

↓ Click command to explain

When to use this

Automatically inject a flag into every invocation of a specific subcommand, useful for enforcing -no-color or -input=false across an entire CI system without editing every script.

Tell Terraform it is running in CI

Advanced Destructive
TF_IN_AUTOMATION=true terraform apply

↓ Click command to explain

When to use this

Tell Terraform it is running in a CI system rather than interactively, which trims some of the suggested next-command hints from output since no human is present to act on them.

Frequently Asked Questions

Terraform is HashiCorp's infrastructure as code tool that lets you define cloud resources such as servers, networks, and databases in a declarative configuration language and have Terraform figure out how to create, update, or destroy the real infrastructure to match. Instead of clicking through a cloud console or writing imperative scripts that create resources step by step, you describe the end state you want, and Terraform computes the difference between that desired state and what actually exists, then applies only the changes needed. This declarative model is what makes Terraform valuable across almost every major cloud provider through the same consistent workflow, so a team that knows Terraform for AWS can apply the same commands and mental model to Azure, Google Cloud, or dozens of smaller providers with only the resource blocks changing.

The reason terraform commands appear in daily engineering work so often is that infrastructure, like application code, changes constantly. New environments get spun up for feature branches, security groups get tightened after an audit, and database instances get resized as traffic grows, and every one of those changes should go through the same reviewable plan and apply cycle rather than a manual console click that nobody can trace later. terraform plan and terraform apply together form the same kind of always reached for read and write loop that kubectl get and aws sts get-caller-identity represent in their own ecosystems, and most real Terraform usage in a mature team is those two commands run repeatedly against a growing set of modules and workspaces.

The single most important mental model for working with Terraform is the state file. Terraform does not inspect your cloud account from scratch on every run. It keeps a JSON record, usually stored remotely in an S3 bucket or Terraform Cloud, that maps every resource block in your configuration to the real object it created, and every plan is really a three way comparison between your configuration, that state file, and the actual infrastructure. Nearly every confusing Terraform error, from a resource that Terraform insists it needs to recreate to one it insists already exists, traces back to state being out of sync with reality in some way, which is exactly why terraform state list, terraform state show, and terraform plan are the first commands worth reaching for when something looks wrong.

Three mistakes account for most of the frustration engineers hit when learning Terraform. The first is running terraform apply without ever looking at the plan output first, since apply without a saved plan generates a brand new plan on the spot that may not match what was reviewed in a pull request. The second is manually editing or deleting resources in the cloud console after they were created by Terraform, which leaves the state file believing a resource exists when it does not, and the next plan either tries to recreate it or throws a confusing error. The third is running terraform destroy or terraform apply in the wrong workspace, because Terraform gives no visual warning about which workspace is active beyond the output of terraform workspace show, so always checking the active workspace before any destructive command is the single habit that prevents the most expensive version of this mistake.