terraform console Command with Examples

Tested on Ubuntu 26.04 LTS (Resolute Raccoon)
Package terraform 1.15.8-1
hashicorp/local 2.9.0
Applies to Any host with Terraform installed
Lab environment Single Ubuntu VM with Terraform — Terraform lab environment on Ubuntu
Privilege Normal user; sudo only if Terraform is not installed yet
Scope Interactive expression evaluation, built-in functions, variables and locals, resource attributes read from state, unknown values with the plan flag, non-interactive piping, state lock behaviour, and common console errors. Does not cover the full function catalogue or a complete expressions tutorial.
Related guides Terraform expressions
Terraform functions
Terraform local values
Terraform variables
Terraform state commands

Writing a for expression or a nested merge() call and finding out whether it works only after terraform apply is a slow way to learn. The terraform console command gives you a read-only prompt where you type an expression and see its value immediately, using the same evaluator that plan and apply use.

That makes it the fastest debugging tool in Terraform. You can check what a local actually resolves to, confirm which key a map lookup returns, or read an attribute of a resource that already exists in state, all without touching a single .tf file.


What does terraform console do?

The console is a REPL: it reads an expression, evaluates it, prints the result, and waits for the next one. Its help text is worth reading once, because the flag list tells you most of what the command can do.

bash
terraform console -help
output
Usage: terraform [global options] console [options]

  Starts an interactive console for experimenting with Terraform
  interpolations.

  This will open an interactive console that you can use to type
  interpolations into and inspect their values. This command loads the
  current state. This lets you explore and test interpolations before
  using them in future configurations.

  This command will never modify your state.

Options:

  -state=path       Legacy option for the local backend only. See the local
                    backend's documentation for more information.

  -plan             Create a new plan (as if running "terraform plan") and
                    then evaluate expressions against its planned state,
                    instead of evaluating against the current state.
                    You can use this to inspect the effects of configuration
                    changes that haven't been applied yet.

  -var 'foo=bar'    Set a variable in the Terraform configuration. This
                    flag can be set multiple times.

  -var-file=foo     Set variables in the Terraform configuration from
                    a file. If "terraform.tfvars" or any ".auto.tfvars"
                    files are present, they will be automatically loaded.

Two sentences in that text matter more than the flags. The console loads the current state, which is why it can show you real resource attributes, and it will never modify your state, which makes plain console mode safe for state inspection. Use -plan with the same caution you would use for a normal plan, because planning can execute data sources or external commands.

A common assumption is that the console needs a configuration before it will start. It does not, as long as you only ask it to evaluate pure expressions. Try it in a directory that contains nothing at all:

bash
mkdir -p ~/terraform-labs/terraform-console/empty

Terraform has no providers to install and no state to read here, so the only thing it can do is compute the expression you hand it:

bash
cd ~/terraform-labs/terraform-console/empty && echo 'upper("hello")' | terraform console
output
"HELLO"

No error, no warning, and no terraform init required. Anything built purely from literals and built-in functions works in an empty directory, which makes the console a handy scratchpad even when you are nowhere near a real project.


Build the lab configuration

To evaluate variables, locals, and resource attributes you need a configuration for the console to load. Create a working directory for this lesson so it stays separate from other Terraform labs:

bash
mkdir -p ~/terraform-labs/terraform-console/main

Declare three input variables covering a string, a list, and a map, so later sections have different types to index into:

bash
cd ~/terraform-labs/terraform-console/main && cat > variables.tf <<'EOF'
variable "environment" {
  type        = string
  default     = "dev"
  description = "Deployment environment name"
}

variable "instance_names" {
  type    = list(string)
  default = ["web-1", "web-2", "web-3"]
}

variable "ports" {
  type = map(number)
  default = {
    http  = 80
    https = 443
  }
}
EOF

Locals are where console debugging pays off most, because a local is derived from other values and you cannot see the result anywhere until something renders it. Add three that build on the variables above:

bash
cat > locals.tf <<'EOF'
locals {
  name = "${var.environment}-web"
  tags = {
    env   = var.environment
    owner = "platform"
  }
  upper_names = [for n in var.instance_names : upper(n)]
}
EOF

Now the resources. The built-in terraform_data resource needs no credentials, and local_file writes a real file so you can compare an attribute Terraform computes against one the provider generates:

bash
cat > main.tf <<'EOF'
terraform {
  required_version = ">= 1.12.0"

  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

resource "terraform_data" "demo" {
  input = "${var.environment}-payload"
}

resource "local_file" "notes" {
  filename = "${path.module}/notes.txt"
  content  = "environment=${var.environment}\n"
}

output "resource_id" {
  value = terraform_data.demo.id
}
EOF

Before initializing, try the console once so you can recognize the failure when it happens to you for real:

bash
echo 'upper("terraform")' | terraform console -no-color
output
Error: Inconsistent dependency lock file

The following dependency selections recorded in the lock file are
inconsistent with the current configuration:
  - provider registry.terraform.io/hashicorp/local: required by this configuration but no version is selected

To make the initial dependency selections that will initialize the dependency
lock file, run:
  terraform init

The expression itself was fine. The console never got as far as evaluating it, because the configuration now declares the local provider and Terraform cannot build an evaluation context until that provider is resolved. This is the honest version of "the console needs init": it needs it once providers or modules enter the picture, not always.

Resolve the provider with terraform init:

bash
terraform init
output
Initializing the backend...

Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Finding hashicorp/local versions matching "~> 2.5"...
- Installing hashicorp/local v2.9.0...
- Installed hashicorp/local v2.9.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above.

Terraform has been successfully initialized!

The ~> 2.5 constraint allows any 2.x release from 2.5 upward, so Terraform picked v2.9.0. The console can now load the full configuration.


Start an interactive session

Opening the console with no flags drops you at a > prompt against the current state:

bash
terraform console
output
> upper("terraform")
"TERRAFORM"
> exit

Type an expression, press Enter, and the value appears on the next line. When you are done, exit closes the session, and Ctrl-D does the same by sending end of file. Both return exit status zero, and Terraform prints exit on the prompt line even when you used Ctrl-D, so the two look identical afterwards. Ctrl-C closes the console as well.

Every remaining example in this guide is shown in its piped form, echo '<expression>' | terraform console, because that produces one clean result per command. Typing the same expression at the > prompt gives you exactly the same value.


Test Terraform expressions and functions

Arithmetic is the quickest way to confirm the console is evaluating rather than echoing. Operator precedence follows the usual rules, so multiplication binds tighter than addition:

bash
echo '2 + 3 * 4' | terraform console
output
14

Parentheses override that precedence, which is worth checking when a nested expression in your configuration produces a number you did not expect:

bash
echo '(2 + 3) * 4' | terraform console
output
20

Division exposes something surprising about how Terraform stores numbers. It does not use a float64 the way most languages would:

bash
echo '10 / 3' | terraform console
output
3.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333332

That is arbitrary-precision decimal arithmetic, not a rounding bug. It rarely matters, but if you feed a division result into a string it will not look like the 3.3333333333333335 you might expect, so round explicitly with ceil, floor, or format when the value ends up in a name or a tag.

Conditionals are the expression type most worth testing before you commit them, because a wrong branch silently produces valid-looking infrastructure:

bash
echo 'var.environment == "dev" ? "t3.small" : "t3.large"' | terraform console
output
"t3.small"

A for expression transforms one collection into another, and the console shows you the shape of the result rather than just its values:

bash
echo '[for n in ["web-1", "web-2"] : upper(n)]' | terraform console
output
[
  "WEB-1",
  "WEB-2",
]

Note the trailing comma after the last element and the multi-line layout. That is how Terraform renders a collection, not a copy-paste artifact.

Indexing into a list uses a zero-based position, which is the source of many off-by-one mistakes in count blocks:

bash
echo 'var.instance_names[0]' | terraform console
output
"web-1"

Map access uses the key instead, and quoting matters because an unquoted key would be read as a variable reference:

bash
echo 'var.ports["https"]' | terraform console
output
443

String functions behave exactly as they will inside a resource argument. format is the one to reach for when you need zero-padded or fixed-width names:

bash
echo 'format("%s-%03d", var.environment, 7)' | terraform console
output
"dev-007"

join collapses a list into a single string, which is how most tag and description fields end up being built:

bash
echo 'join(", ", var.instance_names)' | terraform console
output
"web-1, web-2, web-3"

The reverse direction reveals a detail the documentation glosses over. split returns a value with an explicit type wrapper:

bash
echo 'split("-", "web-1")' | terraform console
output
tolist([
  "web",
  "1",
])

That tolist(...) wrapper tells you the result is a genuine list rather than a tuple, which matters when you pass it somewhere with a strict type constraint. Several collection functions render the same way:

bash
echo 'keys(var.ports)' | terraform console
output
tolist([
  "http",
  "https",
])

Not every collection function wraps its output, though. flatten returns a plain tuple, so the presence or absence of the wrapper is itself information about the type you are getting back:

bash
echo 'flatten([["a"], ["b", "c"]])' | terraform console
output
[
  "a",
  "b",
  "c",
]

merge is the function most often used to combine a common tag map with per-resource additions, and the console confirms which side wins on a key collision:

bash
echo 'merge(local.tags, { tier = "frontend" })' | terraform console
output
{
  "env" = "dev"
  "owner" = "platform"
  "tier" = "frontend"
}

Maps render with = between key and value and no trailing commas, which is how you can tell a map from a list at a glance in console output.

When a key might be missing, lookup supplies a fallback instead of failing:

bash
echo 'lookup(var.ports, "ftp", 21)' | terraform console
output
21

Type conversion is worth rehearsing here because conversion errors during apply are cryptic. Asking Terraform what type it thinks a value has settles arguments quickly:

bash
echo 'type(var.ports)' | terraform console
output
map(number)

The result prints unquoted because type returns a type value rather than a string. For expressions that might fail outright, try returns the first argument that evaluates successfully:

bash
echo 'try(var.ports["ftp"], 21)' | terraform console
output
21

Its companion can turns the same failure into a boolean, which is what variable validation rules are built from:

bash
echo 'can(var.ports["ftp"])' | terraform console
output
false

Evaluate variables, locals, and tfvars overrides

Reading a variable back confirms which value actually reached Terraform, rather than which one you think is in effect:

bash
echo 'var.environment' | terraform console
output
"dev"

Locals are the real reason to open the console. Nothing in your configuration displays local.name until something consumes it, so this is the only quick way to see what it resolved to:

bash
echo 'local.name' | terraform console
output
"dev-web"

A local built by a for expression is even harder to picture from the source, and the console renders the whole collection:

bash
echo 'local.upper_names' | terraform console
output
[
  "WEB-1",
  "WEB-2",
  "WEB-3",
]

You can test a different variable value without editing any file by passing -var when the console starts:

bash
echo 'var.environment' | terraform console -var environment=prod
output
"prod"

The important part is what happens to values derived from that variable. Locals are recomputed against the override rather than left at their original value:

bash
echo 'local.name' | terraform console -var environment=prod
output
"prod-web"

That makes the console a genuine what-if tool: change one input and see every derived value follow, with no plan and no apply. The override lasts only for that invocation.

A terraform.tfvars file in the working directory is loaded automatically, exactly as it would be for plan and apply. Create one to confirm:

bash
printf 'environment = "staging"\n' > terraform.tfvars

The console picks the file up with no flag at all, and the derived local follows it:

bash
echo 'local.name' | terraform console -no-color
output
"staging-web"

Remove the file so the rest of the lab runs against the default:

bash
rm -f terraform.tfvars

Files with other names are not loaded automatically, which is a frequent surprise. Those need -var-file, and this is worth testing once so you recognize the difference:

bash
printf 'environment = "qa"\n' > custom.tfvars

Pointing the console at that file explicitly gives you its value for the session:

bash
echo 'var.environment' | terraform console -var-file=custom.tfvars -no-color
output
"qa"

Clean up the second file before moving on:

bash
rm -f custom.tfvars

Read resource attributes before you apply

Resource attributes are where the console stops being an expression calculator and starts reading your infrastructure. Nothing has been created yet, so check what state currently holds:

bash
terraform state list -no-color
output
No state file was found!

State management commands require a state file. Run this command
in a directory where Terraform has been run or use the -state flag
to point the command to a specific state location.

With no state at all, you might expect referencing a resource to fail. It does not:

bash
echo 'terraform_data.demo.output' | terraform console
output
(known after apply)

The command exits zero and hands back a placeholder. Ask for the whole resource object and every attribute reads the same way:

bash
echo 'terraform_data.demo' | terraform console
output
{
  "id" = (known after apply)
  "input" = (known after apply)
  "output" = (known after apply)
  "triggers_replace" = (known after apply)
}

Even input is unknown here, despite being a literal interpolation of var.environment in the configuration. Plain console mode has no plan data to work from, so it treats the entire object as unresolved. Remember this the next time an expression seems to return nothing useful. It may simply be waiting on an apply.


Work with unknown values using -plan

Plain console mode reads committed state, and with an empty state there is nothing for it to read. The -plan flag changes that. It runs a plan first and evaluates expressions against the planned result, so anything Terraform can compute from your configuration resolves right away.

IMPORTANT
terraform console -plan runs Terraform's planning phase before opening the console. It still does not write state or apply managed-resource changes, but data sources and other plan-time integrations may execute. Treat it with the same operational caution as terraform plan.

The input attribute that was unknown a moment ago makes the difference obvious:

bash
echo 'terraform_data.demo.input' | terraform console -plan
output
"dev-payload"

Same expression, same empty state, real value. The plan filled in what the configuration already determines. Attributes the provider generates behave differently:

bash
echo 'terraform_data.demo.output' | terraform console -plan
output
(known after apply)

output is produced by the provider during creation, so no amount of planning can reveal it early. The local_file resource shows the same split. Its content interpolates only a variable, so it is fully known:

bash
echo 'local_file.notes.content' | terraform console -plan
output
<<EOT
environment=dev

EOT

Its identifier, by contrast, is a hash the provider computes at create time:

bash
echo 'local_file.notes.id' | terraform console -plan
output
(known after apply)

That split is the practical lesson. When an expression still returns (known after apply) under -plan, the value genuinely does not exist yet and no debugging will produce it early. When it returns a real value, your expression is correct and you can stop looking.

Attribute Plain console, empty state With -plan
terraform_data.demo.input (known after apply) "dev-payload"
terraform_data.demo.output (known after apply) (known after apply)
local_file.notes.content (known after apply) known from configuration
local_file.notes.id (known after apply) (known after apply)

Inspect resource attributes after apply

Create the resources so the attributes become real:

bash
terraform apply -auto-approve -no-color
output
Terraform will perform the following actions:

  # local_file.notes will be created
  + resource "local_file" "notes" {
      + content              = <<-EOT
            environment=dev
        EOT
      + filename             = "./notes.txt"
      + id                   = (known after apply)
    }

  # terraform_data.demo will be created
  + resource "terraform_data" "demo" {
      + id     = (known after apply)
      + input  = "dev-payload"
      + output = (known after apply)
    }

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

terraform_data.demo: Creating...
terraform_data.demo: Creation complete after 0s [id=a1809f27-ad4b-9978-ec2e-8ef861ef67d3]
local_file.notes: Creating...
local_file.notes: Creation complete after 0s [id=1685b7a32904c8d97e4170def7199024e268bfb3]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

resource_id = "a1809f27-ad4b-9978-ec2e-8ef861ef67d3"

Both resources exist now, so the same expression resolves to a concrete value:

bash
echo 'terraform_data.demo.output' | terraform console
output
"dev-payload"

Reading the full object shows the difference from the pre-apply view, including an attribute that was never set:

bash
echo 'terraform_data.demo' | terraform console
output
{
  "id" = "a1809f27-ad4b-9978-ec2e-8ef861ef67d3"
  "input" = "dev-payload"
  "output" = "dev-payload"
  "triggers_replace" = null
}

triggers_replace reads as null rather than (known after apply), and that distinction is useful: null means the value is settled and empty, while the placeholder means Terraform does not know it yet.

Multi-line strings render in heredoc form, which catches people out when they compare a console result against a literal in their configuration:

bash
echo 'local_file.notes.content' | terraform console
output
<<EOT
environment=dev

EOT

The blank line before EOT is the trailing newline in the file content, not a formatting quirk. Your terraform_data ID will differ from the one above, since the provider generates a fresh UUID on every create. For listing and filtering state rather than evaluating it, terraform state commands are the better tool.


Run terraform console non-interactively

Piping a single expression into the console is the pattern used throughout this guide, and it is genuinely useful in a shell script or a quick one-liner:

bash
echo 'upper("terraform")' | terraform console
output
"TERRAFORM"

There is a trap here that costs people a lot of time. Feed several expressions in and only one result comes back:

bash
terraform console <<'EOF'
var.environment
local.name
length(var.instance_names)
EOF
output
3

Two expressions vanished without a word. This is documented rather than a bug: when you pipe newline-separated commands in, only the output of the final one is printed unless an error occurs earlier. There is no warning, and the exit status is still zero. Reordering the lines confirms it is positional rather than a parsing failure, since whichever expression comes last is the one you get.

The same behaviour explains a confusing empty result. Piping exit after your expression throws away the answer you wanted:

bash
printf 'upper("a")\nexit\n' | terraform console -no-color

The command prints nothing at all and still exits zero, because exit was the last thing evaluated. Never append exit to piped input; end-of-file closes the console on its own.

So keep non-interactive use to one expression per invocation. When you need several values in a script, call the console once per expression, or reach for terraform output with -json if the values are already exposed as outputs.


Does terraform console lock your state?

Yes, and you should work as though it does. HashiCorp documents that the console holds a lock on the state, and that you cannot use the console while another operation that modifies state is running. Against a shared backend, treat an open prompt as a state-locking operation and do not count on a concurrent apply going through.

That documented contract is the rule to follow. It is still worth knowing where the lock lives and how to look for it, because that is the same file Terraform consults when an operation refuses to start. Open terraform console in a second terminal and leave it at the prompt, then check from your first terminal for the lock file the local backend writes:

bash
ls -la .terraform.tfstate.lock.info
output
ls: cannot access '.terraform.tfstate.lock.info': No such file or directory

On the lab built for this article the file was absent while the console sat at the prompt. A file check can also miss a lock that is held only briefly, so the stronger check is to attempt a state-writing operation with a short timeout while the session is still open:

bash
terraform apply -auto-approve -lock-timeout=5s -no-color
output
terraform_data.demo: Refreshing state... [id=a1809f27-ad4b-9978-ec2e-8ef861ef67d3]
local_file.notes: Refreshing state... [id=1685b7a32904c8d97e4170def7199024e268bfb3]

No changes. Your infrastructure matches the configuration.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

The apply finished straight away instead of waiting out its five second timeout, and starting the console with -plan behaved the same way. That is not the documented behaviour, so read it as something specific to this build and backend rather than as permission to run operations side by side.

For contrast, this is what a held lock looks like. Start an ordinary apply, and read the lock file from your other terminal while that apply is still running:

bash
cat .terraform.tfstate.lock.info
output
{"ID":"3434dd0f-6f54-0d57-132b-c6d28d8882c3","Operation":"OperationTypeApply","Info":"","Who":"root@golinuxcloud","Version":"1.15.8","Created":"2026-08-12T11:13:26.793016542Z","Path":"terraform.tfstate"}

The lock appears within roughly a tenth of a second and names the operation holding it, which is what Terraform reports back as Error acquiring the state lock. Remote backends implement locking their own way, and Terraform state locking covers those differences. Keep the documented rule as your working assumption: expect the console to lock state, and do not schedule state-writing commands against a working directory where somebody has a console open. What holds in every case is that the console itself never writes state, so an open session cannot corrupt it.


Common terraform console problems

Most console errors share the same frame, naming <console-input> line 1 with the source unavailable, because your expression was typed rather than read from a file. The heading on the first line is the part that tells you what went wrong.

Indexing past the end of a collection is the most common one, and the message names the cause precisely:

bash
echo 'var.instance_names[10]' | terraform console -no-color
output
Error: Invalid index

  on <console-input> line 1:
  (source code not available)

The given key does not identify an element in this collection value.

Attribute access on the wrong kind of value produces a different detail line under the same heading, which is the fastest way to tell a missing map key from a mistyped variable:

bash
echo 'var.environment.foo' | terraform console -no-color
output
Error: Unsupported attribute

  on <console-input> line 1:
  (source code not available)

Can't access attributes on a primitive-typed value (string).

A broken configuration stops the console before it evaluates anything. Even a perfectly valid expression fails, because the working directory must parse first:

bash
cd ~/terraform-labs/terraform-console/errors && echo 'upper("test")' | terraform console -no-color
output
Error: Invalid expression

  on main.tf line 2, in resource "local_file" "broken":
   2:   filename = 
   3: }

Expected the start of an expression, but found an invalid expression token.

The error points at main.tf rather than at your input. That is a reliable signal that the problem is the directory, not the expression you typed. Fix the configuration, or change into a directory that parses, and the prompt opens normally. For wider diagnosis, the Terraform troubleshooting guide covers the same errors as they appear during plan and apply.

Symptom Likely cause Fix
Inconsistent dependency lock file Configuration declares a provider that is not yet resolved Run terraform init in the working directory
Invalid expression naming a .tf file Configuration in the current directory does not parse Fix the named file, or run the console elsewhere
Reference to undeclared input variable Variable name typed wrongly, or no variable block for it Check the spelling against variables.tf
Reference to undeclared resource Resource address does not exist in the root module Confirm the type and name with terraform state list
Unsupported attribute Attribute missing, or attribute access on a string or number Read the detail line — it distinguishes the two cases
Invalid index List index out of range, or map key absent Check length() first, or use lookup() with a default
Call to unknown function Function name misspelled or does not exist Check the spelling against the function list
Missing expression Unbalanced parentheses or truncated input Close the expression before pressing Enter
Result is (known after apply) Value is generated by the provider at create time Apply first, or accept that it cannot be known early
Piped input prints only one value Standard input is not a terminal Run one expression per invocation
Piped input prints nothing exit was the last line of the piped input Remove exit; end-of-file closes the console

Clean up the lab

The console created nothing, but the apply in this walkthrough did. Remove both resources so the working directory is back where it started:

bash
cd ~/terraform-labs/terraform-console/main && terraform destroy -auto-approve -no-color
output
terraform_data.demo: Refreshing state... [id=a1809f27-ad4b-9978-ec2e-8ef861ef67d3]
local_file.notes: Refreshing state... [id=1685b7a32904c8d97e4170def7199024e268bfb3]

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

Changes to Outputs:
  - resource_id = "a1809f27-ad4b-9978-ec2e-8ef861ef67d3" -> null
terraform_data.demo: Destroying... [id=a1809f27-ad4b-9978-ec2e-8ef861ef67d3]
terraform_data.demo: Destruction complete after 0s
local_file.notes: Destroying... [id=1685b7a32904c8d97e4170def7199024e268bfb3]
local_file.notes: Destruction complete after 0s

Destroy complete! Resources: 2 destroyed.

The notes.txt file went with the local_file resource. Confirm the state is empty rather than assuming it:

bash
terraform state list -no-color

An empty state prints nothing at all and exits zero, which is the same silence you saw before anything existed. Terraform keeps terraform.tfstate as an empty shell and writes the previous contents to terraform.tfstate.backup.


References


Summary

The terraform console command turns expression debugging from a plan-and-wait cycle into an immediate answer. You opened a prompt, evaluated arithmetic, conditionals, for expressions, and a spread of string and collection functions, then moved on to the values that only exist inside your project: input variables, derived locals, and resource attributes read straight from state. Passing -var at startup let you change one input and watch every dependent local recompute, which is the closest thing Terraform has to a what-if calculator.

Two behaviours are worth carrying away because they look like bugs. Referencing a resource before you apply returns (known after apply) rather than an error, and in plain console mode the whole object reads that way even for attributes your configuration defines literally. Running with -plan separates the two cases properly: values Terraform derives from configuration resolve, while provider-generated identifiers stay unknown until creation. The other trap is piping several expressions at once, which silently prints only the last result. Outside an interactive session, keep to one expression per invocation.

Treat the console as a state-locking operation. HashiCorp documents that it holds a lock on state and that you cannot use it while another state-modifying operation runs, so on a shared backend do not leave a prompt open and expect a colleague's apply to go through. The lab in this guide happened to allow a concurrent apply on the local backend, which is a useful reminder that observed behaviour and the documented contract are not always the same thing, but the contract is what you should design your workflow around. One safety property does hold in every case: the console never writes state.

Open the console the next time an expression in your configuration produces something unexpected. Paste the expression at the prompt, compare what you get against what you assumed, and reach for -plan when the answer comes back as a placeholder rather than a value.


Frequently Asked Questions

1. Does terraform console change my infrastructure?

terraform console never writes Terraform state or directly creates, updates, or destroys managed resources. However, terraform console -plan first runs Terraform's planning phase, so data sources or external commands that execute during planning can still contact or affect external systems. Treat -plan with the same care as terraform plan.

2. Do I need to run terraform init before terraform console?

Only when the configuration declares providers or modules that must be resolved first. In a directory with no configuration files at all, the console starts immediately and evaluates pure expressions such as upper hello without any initialization.

3. Why does terraform console print only one result when I pipe several expressions?

When standard input is a pipe rather than a terminal, the console evaluates the input and prints the result of the final expression only, discarding the earlier ones silently. Run one expression per invocation, or use a real interactive session when you need several results.

4. What does known after apply mean in terraform console?

It marks a value Terraform cannot determine yet because the provider generates it during creation. Reading a resource attribute before you apply returns that placeholder rather than an error, so an expression can look broken when it is simply unresolved.

5. How do I exit terraform console?

Type exit and press Enter, or press Ctrl-D to send end of file, or press Ctrl-C. The exit and Ctrl-D paths both return exit status zero, and Terraform prints exit on the prompt line in either case, so the two look identical in a transcript.

6. Can terraform console evaluate a variable value without editing tfvars files?

Yes. Pass -var name=value when you start the console, and any locals derived from that variable recompute against the overridden value for that session only. A -var-file flag loads a file that is not picked up automatically.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)