{"id":79385,"date":"2026-10-15T09:29:28","date_gmt":"2026-10-15T09:29:28","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=79385"},"modified":"2026-10-15T10:19:01","modified_gmt":"2026-10-15T10:19:01","slug":"hcp-terraform-terraform-cloud-complete-guide-to-variables-scope-precedence","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/hcp-terraform-terraform-cloud-complete-guide-to-variables-scope-precedence\/","title":{"rendered":"HCP Terraform (Terraform Cloud) \u2014 Complete Guide to Variables, Scope &amp; Precedence"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17-1024x683.png\" alt=\"\" class=\"wp-image-79389\" srcset=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17-1024x683.png 1024w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17-300x200.png 300w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17-768x512.png 768w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-17.png 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Updated: October 2026 | Based on current HashiCorp documentation<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HCP Terraform provides several ways to pass values to Terraform code. These include variable defaults, <code>.tfvars<\/code> files, environment variables, workspace variables, project\/organization variable sets, and run-specific CLI arguments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The three most important things to understand are:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Type: Is it a Terraform input variable or an environment variable?<\/li>\n\n\n\n<li>Scope: Does the value apply to one run, one workspace, a project, or the entire organization?<\/li>\n\n\n\n<li>Precedence: When the same variable is defined in multiple places, which value wins?<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">One particularly important rule: Workspace variables normally override variable sets, but Priority Variable Sets can override even workspace variables and command-line values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Two types of variables in HCP Terraform<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Feature<\/th><th>Terraform variable<\/th><th>Environment variable<\/th><\/tr><tr><td>Purpose<\/td><td>Configure Terraform resources and modules<\/td><td>Configure providers, authentication and Terraform execution<\/td><\/tr><tr><td>Example<\/td><td><code>instance_type<\/code><\/td><td><code>AWS_REGION<\/code><\/td><\/tr><tr><td>Access in <code>.tf<\/code> code<\/td><td><code>var.instance_type<\/code><\/td><td>Usually through provider or Terraform process behavior<\/td><\/tr><tr><td>Workspace UI category<\/td><td>Terraform Variable<\/td><td>Environment Variable<\/td><\/tr><tr><td>Supports HCL checkbox<\/td><td>Yes<\/td><td>No<\/td><\/tr><tr><td>Supports Sensitive flag<\/td><td>Yes<\/td><td>Yes<\/td><\/tr><tr><td>Can be in variable sets<\/td><td>Yes<\/td><td>Yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Example A: Terraform input variable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In <code>variables.tf<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">variable <span class=\"hljs-string\">\"instance_type\"<\/span> {\n  description = <span class=\"hljs-string\">\"EC2 instance type\"<\/span>\n  type        = string\n  <span class=\"hljs-keyword\">default<\/span>     = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In HCP Terraform, configure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">Category<\/span>: Terraform variable\n<span class=\"hljs-attribute\">Key<\/span>:      instance_type\n<span class=\"hljs-attribute\">Value<\/span>:    t3.medium<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">And access it in code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">resource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"example\"<\/span> {\n  ami           = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type = <span class=\"hljs-keyword\">var<\/span>.instance_type\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Terraform uses <code>t3.medium<\/code>, overriding the default <code>t3.micro<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example B: Environment variable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In HCP Terraform:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">Category<\/span>: Environment variable\n<span class=\"hljs-attribute\">Key<\/span>:      AWS_REGION\n<span class=\"hljs-attribute\">Value<\/span>:    ap-northeast-1<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Terraform&#8217;s AWS provider can consume the environment variable:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">provider <span class=\"hljs-string\">\"aws\"<\/span> {\n  <span class=\"hljs-comment\"># Region may be supplied by AWS_REGION<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Important: <code>AWS_REGION<\/code> does not automatically become <code>var.aws_region<\/code>. If you want <code>var.aws_region<\/code>, declare an input variable and provide its value through a Terraform variable or <code>TF_VAR_aws_region<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For AWS authentication, prefer OIDC-based dynamic provider credentials over permanent access keys.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. All ways to set and pass variable values<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Method<\/th><th>Where defined<\/th><th>Scope<\/th><th>Example<\/th><\/tr><tr><td>Default value<\/td><td><code>variables.tf<\/code><\/td><td>Terraform configuration<\/td><td><code>default = \"t3.micro\"<\/code><\/td><\/tr><tr><td><code>terraform.tfvars<\/code><\/td><td>Repository \/ configuration directory<\/td><td>Configuration<\/td><td><code>instance_type = \"t3.small\"<\/code><\/td><\/tr><tr><td><code>*.auto.tfvars<\/code><\/td><td>Repository \/ configuration directory<\/td><td>Configuration<\/td><td><code>instance_type = \"t3.medium\"<\/code><\/td><\/tr><tr><td><code>*.tfvars.json<\/code><\/td><td>Repository \/ configuration directory<\/td><td>Configuration<\/td><td>JSON-formatted inputs<\/td><\/tr><tr><td><code>TF_VAR_*<\/code><\/td><td>Shell environment<\/td><td>Current process \/ run<\/td><td><code>TF_VAR_instance_type<\/code><\/td><\/tr><tr><td>CLI <code>-var<\/code><\/td><td>Terraform command<\/td><td>Single run<\/td><td><code>-var=\"instance_type=t3.large\"<\/code><\/td><\/tr><tr><td>CLI <code>-var-file<\/code><\/td><td>Terraform command<\/td><td>Single run<\/td><td><code>-var-file=prod.tfvars<\/code><\/td><\/tr><tr><td>Workspace variable<\/td><td>HCP Terraform UI\/API<\/td><td>One workspace<\/td><td><code>instance_type = t3.xlarge<\/code><\/td><\/tr><tr><td>Workspace-scoped variable set<\/td><td>HCP Terraform<\/td><td>Selected workspaces<\/td><td>Shared configuration<\/td><\/tr><tr><td>Project-scoped variable set<\/td><td>HCP Terraform<\/td><td>All workspaces in project<\/td><td>Shared project settings<\/td><\/tr><tr><td>Global variable set<\/td><td>HCP Terraform<\/td><td>All organization workspaces<\/td><td>Organization defaults<\/td><\/tr><tr><td>Priority variable set<\/td><td>HCP Terraform<\/td><td>Selected scope, enforced precedence<\/td><td>Protected configuration<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You can also create and update workspace variables and variable sets programmatically using the HCP Terraform API or the Terraform <code>tfe<\/code> provider. These are management methods, not additional precedence levels.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Variable scope mapping<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"634\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-15.png\" alt=\"\" class=\"wp-image-79386\" srcset=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-15.png 799w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-15-300x238.png 300w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-15-767x609.png 767w\" sizes=\"auto, (max-width: 799px) 100vw, 799px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Who owns a variable set vs where it applies?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These are separate concepts in modern HCP Terraform.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Ownership<\/th><th>Assignment scope<\/th><th>Effect<\/th><\/tr><tr><td>Organization-owned<\/td><td>Global<\/td><td>Every workspace in the organization<\/td><\/tr><tr><td>Organization-owned<\/td><td>Specific projects<\/td><td>All workspaces in selected projects<\/td><\/tr><tr><td>Organization-owned<\/td><td>Specific workspaces<\/td><td>Only selected workspaces<\/td><\/tr><tr><td>Project-owned<\/td><td>Entire project<\/td><td>All workspaces in that project<\/td><\/tr><tr><td>Project-owned<\/td><td>Specific workspaces<\/td><td>Only selected workspaces within that project<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A project does not have a separate ordinary variable-value layer. Project-wide values are provided through variable sets.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Similarly, Teams and Users manage access permissions; they are not variable scopes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Complete HCP Terraform variable precedence<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is the most important reference table.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Highest priority at the top. The first applicable source with a matching variable type and key wins.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Rank<\/th><th>Variable source<\/th><th>Priority enabled<\/th><\/tr><tr><td>1<\/td><td>Global variable set<\/td><td>Yes<\/td><\/tr><tr><td>2<\/td><td>Organization-owned, project-scoped variable set<\/td><td>Yes<\/td><\/tr><tr><td>3<\/td><td>Organization-owned, workspace-scoped variable set<\/td><td>Yes<\/td><\/tr><tr><td>4<\/td><td>Project-owned, project-scoped variable set<\/td><td>Yes<\/td><\/tr><tr><td>5<\/td><td>Project-owned, workspace-scoped variable set<\/td><td>Yes<\/td><\/tr><tr><td>6<\/td><td>CLI <code>-var<\/code> \/ <code>-var-file<\/code><\/td><td>N\/A<\/td><\/tr><tr><td>7<\/td><td>Local <code>TF_VAR_*<\/code> for CLI-driven remote runs<\/td><td>N\/A<\/td><\/tr><tr><td>8<\/td><td>Workspace-specific variable<\/td><td>N\/A<\/td><\/tr><tr><td>9<\/td><td>Project-owned, workspace-scoped variable set<\/td><td>No<\/td><\/tr><tr><td>10<\/td><td>Project-owned, project-scoped variable set<\/td><td>No<\/td><\/tr><tr><td>11<\/td><td>Organization-owned, workspace-scoped variable set<\/td><td>No<\/td><\/tr><tr><td>12<\/td><td>Organization-owned, project-scoped variable set<\/td><td>No<\/td><\/tr><tr><td>13<\/td><td>Global variable set<\/td><td>No<\/td><\/tr><tr><td>14<\/td><td><code>*.auto.tfvars<\/code> files<\/td><td>N\/A<\/td><\/tr><tr><td>15<\/td><td><code>terraform.tfvars<\/code><\/td><td>N\/A<\/td><\/tr><tr><td>\u2014<\/td><td>Terraform input variable <code>default<\/code><\/td><td>Lowest fallback<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This is the precedence order published in HashiCorp&#8217;s current HCP Terraform documentation. It also explains why ownership and Priority status can matter more than the apparent specificity of the scope.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The table focuses on HCP Terraform&#8217;s published tiers. Terraform also supports the JSON variants <code>*.auto.tfvars.json<\/code> and <code>terraform.tfvars.json<\/code>; their ordering follows Terraform&#8217;s normal variable-file rules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Five rules worth memorizing<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A workspace variable overrides normal, non-priority variable sets.<\/li>\n\n\n\n<li>Run-specific CLI values override workspace variables, unless a matching Priority Variable Set takes precedence.<\/li>\n\n\n\n<li>A Priority Global Variable Set has the highest precedence.<\/li>\n\n\n\n<li>Within otherwise equal variable sets, the set whose name sorts first lexically wins. For example, <code>A-settings<\/code> wins over <code>B-settings<\/code>.<\/li>\n\n\n\n<li>Two global variable sets cannot define conflicting variables of the same key and type.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike the normal non-priority case, an organization-owned priority set can outrank a project-owned priority set, as shown in the ranking.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Interactive precedence example<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose <code>node_count<\/code> is defined at several levels for the same workspace.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"715\" height=\"698\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-16.png\" alt=\"\" class=\"wp-image-79387\" srcset=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-16.png 715w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2026\/10\/image-16-300x293.png 300w\" sizes=\"auto, (max-width: 715px) 100vw, 715px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The CLI override represents a CLI-driven run. The priority example uses the documented HCP Terraform precedence order.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example: What happens when values conflict?<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Source<\/th><th><code>node_count<\/code><\/th><\/tr><tr><td><code>variables.tf<\/code> default<\/td><td>1<\/td><\/tr><tr><td><code>terraform.tfvars<\/code><\/td><td>2<\/td><\/tr><tr><td><code>dev.auto.tfvars<\/code><\/td><td>3<\/td><\/tr><tr><td>Normal project variable set<\/td><td>5<\/td><\/tr><tr><td>Workspace variable<\/td><td>6<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The effective value is 6, because the workspace variable overrides the lower-ranked sources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you now run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"node_count=7\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The effective value becomes 7 in a CLI-driven remote run.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But if a Priority Global Variable Set defines <code>node_count = 8<\/code>, then the effective value becomes 8, even when the CLI specifies 7.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Practical examples for each method<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Method A \u2014 Values in <code>.tfvars<\/code> files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>terraform.tfvars<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">node_count = <span class=\"hljs-number\">2<\/span>\nenvironment = <span class=\"hljs-string\">\"development\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>production.auto.tfvars<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">node_count = <span class=\"hljs-number\">3<\/span>\nenvironment = <span class=\"hljs-string\">\"production\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Terraform automatically reads these files when they are included in the configuration. The <code>*.auto.tfvars<\/code> values have precedence over <code>terraform.tfvars<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A custom file such as <code>production.tfvars<\/code> must be explicitly supplied using <code>-var-file<\/code> rather than relying on automatic loading.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method B \u2014 <code>TF_VAR_*<\/code> in your terminal<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> TF_VAR_node_count=<span class=\"hljs-number\">4<\/span>\n<span class=\"hljs-keyword\">export<\/span> TF_VAR_environment=<span class=\"hljs-string\">\"staging\"<\/span>\n\nterraform plan<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">With a CLI-driven HCP Terraform remote run, these inputs can override workspace variables and normal variable sets. They do not replace the provider credentials and other execution-environment settings required in HCP Terraform.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method C \u2014 Complex values through Workspace Variables<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">variable <span class=\"hljs-string\">\"subnet_ids\"<\/span> {\n  type = <span class=\"hljs-keyword\">list<\/span>(string)\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">HCP Terraform UI:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">Category<\/span>: <span class=\"hljs-selector-tag\">Terraform<\/span>\n<span class=\"hljs-selector-tag\">Key<\/span>: <span class=\"hljs-selector-tag\">subnet_ids<\/span>\n\n<span class=\"hljs-selector-tag\">Value<\/span>:\n<span class=\"hljs-selector-attr\">&#91;<span class=\"hljs-string\">\"subnet-abc123\"<\/span>, <span class=\"hljs-string\">\"subnet-def456\"<\/span>]<\/span>\n\n<span class=\"hljs-selector-tag\">HCL<\/span>: <span class=\"hljs-selector-tag\">Enabled<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For lists, maps and objects, enable the HCL checkbox when entering HCL expressions in the HCP Terraform UI.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method D \u2014 Set variables through the HCP Terraform Runs API<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Runs API also supports run-specific values. For example, a run creation payload may include:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"data\"<\/span>: {\n    <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"runs\"<\/span>,\n    <span class=\"hljs-attr\">\"attributes\"<\/span>: {\n      <span class=\"hljs-attr\">\"variables\"<\/span>: &#91;\n        {\n          <span class=\"hljs-attr\">\"key\"<\/span>: <span class=\"hljs-string\">\"node_count\"<\/span>,\n          <span class=\"hljs-attr\">\"value\"<\/span>: <span class=\"hljs-string\">\"5\"<\/span>\n        }\n      ]\n    },\n    <span class=\"hljs-attr\">\"relationships\"<\/span>: {\n      <span class=\"hljs-attr\">\"workspace\"<\/span>: {\n        <span class=\"hljs-attr\">\"data\"<\/span>: {\n          <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"workspaces\"<\/span>,\n          <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-string\">\"ws-EXAMPLE\"<\/span>\n        }\n      }\n    }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These are supplied to a particular run, rather than permanently updating the workspace. Values must be valid HCL literals. This is useful for CI\/CD orchestration and automation.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method E \u2014 Manage HCP Terraform variables using Terraform<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can manage the platform&#8217;s variable configuration through the official <code>hashicorp\/tfe<\/code> provider:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">resource <span class=\"hljs-string\">\"tfe_variable\"<\/span> <span class=\"hljs-string\">\"example\"<\/span> {\n  workspace_id = tfe_workspace.example.id\n\n  key      = <span class=\"hljs-string\">\"instance_type\"<\/span>\n  value    = <span class=\"hljs-string\">\"t3.medium\"<\/span>\n  category = <span class=\"hljs-string\">\"terraform\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This creates a workspace Terraform variable with the normal workspace-variable precedence. The <code>tfe_variable_set<\/code>, <code>tfe_project_variable_set<\/code>, and <code>tfe_workspace_variable_set<\/code> resources support reusable sets and their assignments.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/registry.terraform.io&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform Registry<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">+1<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Critical difference: Execution mode and workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The HCP Terraform execution model affects which sources are available.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Execution \/ workflow<\/th><th>Workspace variables<\/th><th>Variable sets<\/th><th>Local CLI overrides<\/th><\/tr><tr><td>VCS-driven remote<\/td><td>Yes<\/td><td>Yes<\/td><td>Not supplied by VCS runs<\/td><\/tr><tr><td>UI-triggered remote<\/td><td>Yes<\/td><td>Yes<\/td><td>Not from user&#8217;s local shell<\/td><\/tr><tr><td>CLI-driven remote<\/td><td>Yes<\/td><td>Yes<\/td><td>Yes<\/td><\/tr><tr><td>API-driven remote<\/td><td>Yes<\/td><td>Yes<\/td><td>Run-specific API values<\/td><\/tr><tr><td>Agent execution<\/td><td>Yes<\/td><td>Yes<\/td><td>When CLI-driven<\/td><\/tr><tr><td>Local execution mode<\/td><td>No<\/td><td>No<\/td><td>Standard local Terraform precedence<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">+2<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Local execution mode exception is especially important. Even though Terraform state is stored in HCP Terraform, HCP Terraform does not evaluate its workspace variables or variable sets for local execution.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Likewise, in CLI-driven remote runs, shell variables on your laptop such as <code>AWS_ACCESS_KEY_ID<\/code> are not automatically forwarded as remote provider credentials. Configure the execution environment in HCP Terraform or use dynamic authentication.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Recommended variable design for AWS infrastructure<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For a real infrastructure project, I recommend separating shared configuration, environment-specific settings and authentication.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Variable<\/th><th>Type<\/th><th>Recommended scope<\/th><\/tr><tr><td><code>default_tags<\/code><\/td><td>Terraform<\/td><td>Organization-owned variable set or project set<\/td><\/tr><tr><td><code>environment<\/code><\/td><td>Terraform<\/td><td>Workspace<\/td><\/tr><tr><td><code>aws_region<\/code><\/td><td>Terraform<\/td><td>Project set or workspace<\/td><\/tr><tr><td><code>vpc_cidr<\/code><\/td><td>Terraform<\/td><td>Workspace<\/td><\/tr><tr><td><code>eks_cluster_name<\/code><\/td><td>Terraform<\/td><td>Workspace<\/td><\/tr><tr><td><code>node_count<\/code><\/td><td>Terraform<\/td><td>Workspace<\/td><\/tr><tr><td><code>TF_LOG<\/code><\/td><td>Environment<\/td><td>Workspace, only for debugging<\/td><\/tr><tr><td><code>TFC_AWS_PROVIDER_AUTH<\/code><\/td><td>Environment<\/td><td>Workspace or relevant variable set<\/td><\/tr><tr><td><code>TFC_AWS_RUN_ROLE_ARN<\/code><\/td><td>Environment<\/td><td>Workspace or relevant variable set<\/td><\/tr><tr><td>Database password<\/td><td>Sensitive Terraform or provider environment variable<\/td><td>Workspace or restricted variable set<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For AWS dynamic credentials, configure the HCP Terraform OIDC integration and required environment variables such as:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">TFC_AWS_PROVIDER_AUTH = <span class=\"hljs-literal\">true<\/span>\n\nTFC_AWS_RUN_ROLE_ARN =\narn:aws:iam::<span class=\"hljs-number\">123456789012<\/span>:role\/terraform-role<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These values configure HCP Terraform authentication rather than declaring application-level input variables.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">9. Other ways values reach Terraform code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Not every value used by Terraform comes from input variables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Child-module inputs are passed explicitly from the root module:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"vpc\"<\/span> {\n  source = <span class=\"hljs-string\">\".\/modules\/vpc\"<\/span>\n\n  cidr = <span class=\"hljs-keyword\">var<\/span>.vpc_cidr\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Workspace outputs can provide values to another workspace through provider data sources or <code>tfe_outputs<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">data <span class=\"hljs-string\">\"tfe_outputs\"<\/span> <span class=\"hljs-string\">\"network\"<\/span> {\n  organization = <span class=\"hljs-string\">\"my-org\"<\/span>\n  workspace    = <span class=\"hljs-string\">\"network-prod\"<\/span>\n}\n\noutput <span class=\"hljs-string\">\"vpc_id_from_network\"<\/span> {\n  value = data.tfe_outputs.network.nonsensitive_values.vpc_id\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">These fetched values are resolved through data sources and do not participate in the input-variable precedence table.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/registry.terraform.io&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform Registry<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">+1<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Terraform Stacks, variable sets work differently: Stacks reference selected sets explicitly through <code>store<\/code> blocks, rather than using the workspace precedence hierarchy.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">10. Best practices and common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Prefer variable sets for shared values and workspace variables for environment-specific values.<\/li>\n\n\n\n<li>Avoid duplicate keys across multiple non-priority sets unless overriding them is intentional.<\/li>\n\n\n\n<li>Use Priority Variable Sets selectively, because they can prevent workspace teams from overriding values.<\/li>\n\n\n\n<li>Do not place secrets in committed <code>.tfvars<\/code> files.<\/li>\n\n\n\n<li>Mark sensitive HCP Terraform values appropriately, while remembering that Sensitive does not guarantee secrets stay out of Terraform state.<\/li>\n\n\n\n<li>Use dynamic provider credentials rather than persistent AWS access keys.<\/li>\n\n\n\n<li>Check the workspace Variables page for OVERWRITTEN markers when debugging conflicts.<\/li>\n\n\n\n<li>Treat changing a widely shared variable set as a potentially multi-workspace infrastructure change.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.google.com\/s2\/favicons?domain=https:\/\/developer.hashicorp.com&amp;sz=32\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp Developer<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">+1<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final reference: Which source should I use?<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Requirement<\/th><th>Best choice<\/th><\/tr><tr><td>General fallback value<\/td><td>Variable <code>default<\/code><\/td><\/tr><tr><td>Environment configuration maintained in Git<\/td><td><code>.auto.tfvars<\/code><\/td><\/tr><tr><td>Common configuration across organization<\/td><td>Global variable set<\/td><\/tr><tr><td>Shared configuration for one project<\/td><td>Project-scoped variable set<\/td><\/tr><tr><td>Different value for every workspace<\/td><td>Workspace variable<\/td><\/tr><tr><td>Single execution override<\/td><td>CLI <code>-var<\/code> \/ <code>-var-file<\/code> or run API<\/td><\/tr><tr><td>Provider credentials<\/td><td>Dynamic credentials \/ environment variables<\/td><\/tr><tr><td>Centrally enforced configuration<\/td><td>Priority variable set, with policy enforcement where necessary<\/td><\/tr><tr><td>Values from another Terraform deployment<\/td><td>Provider data source \/ <code>tfe_outputs<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The overall rule is that scope determines where a variable applies, while precedence determines which value wins. Ownership and Priority settings are the two HCP Terraform-specific details that make this different from ordinary local Terraform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Official documentation: <a href=\"https:\/\/developer.hashicorp.com\/terraform\/cloud-docs\/variables\">HCP Terraform Variables &amp; Precedence<\/a>, <a href=\"https:\/\/developer.hashicorp.com\/terraform\/cloud-docs\/variables\/managing-variables\">Manage Variables and Variable Sets<\/a>, and <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/values\/variables\">Terraform Input Variable Precedence<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Updated: October 2026 | Based on current HashiCorp documentation HCP Terraform provides several ways to pass values to Terraform code. These include variable defaults, .tfvars files, environment&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-79385","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79385","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=79385"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79385\/revisions"}],"predecessor-version":[{"id":79390,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79385\/revisions\/79390"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=79385"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=79385"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=79385"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}