{"id":1245,"date":"2026-10-15T10:17:32","date_gmt":"2026-10-15T10:17:32","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1245"},"modified":"2026-10-15T10:22:55","modified_gmt":"2026-10-15T10:22:55","slug":"hcp-terraform-cloud-cli-complete-master-tutorial","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/hcp-terraform-cloud-cli-complete-master-tutorial\/","title":{"rendered":"HCP Terraform Cloud CLI \u2014 Complete Master Tutorial"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">HCP Terraform Cloud \u2014 CLI Command Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Organization: <code>motoshare<\/code> | Project: <code>proezi<\/code><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>#<\/th><th>Cloud operation<\/th><th>Command \/ Example<\/th><th>Usage<\/th><\/tr><tr><td>1<\/td><td>Login to Terraform Cloud<\/td><td><code>terraform login<\/code><\/td><td>Authenticate with HCP Terraform<\/td><\/tr><tr><td>2<\/td><td>Login to specific hostname<\/td><td><code>terraform login app.terraform.io<\/code><\/td><td>Authenticate explicitly with Terraform Cloud<\/td><\/tr><tr><td>3<\/td><td>Logout<\/td><td><code>terraform logout<\/code><\/td><td>Remove locally saved credentials<\/td><\/tr><tr><td>4<\/td><td>Authenticate using token<\/td><td><code>export TF_TOKEN_app_terraform_io=\"$TFC_TOKEN\"<\/code><\/td><td>Authenticate from CI\/CD without interactive login<\/td><\/tr><tr><td>5<\/td><td>Set Cloud organization<\/td><td><code>export TF_CLOUD_ORGANIZATION=motoshare<\/code><\/td><td>Configure organization when omitted from the <code>cloud<\/code> block<\/td><\/tr><tr><td>6<\/td><td>Set Cloud project<\/td><td><code>export TF_CLOUD_PROJECT=proezi<\/code><\/td><td>Configure project when omitted from the <code>cloud<\/code> block<\/td><\/tr><tr><td>7<\/td><td>Set Cloud workspace<\/td><td><code>export TF_WORKSPACE=proezi_dev<\/code><\/td><td>Select an existing workspace when cloud configuration permits<\/td><\/tr><tr><td>8<\/td><td>Connect to Terraform Cloud<\/td><td><code>terraform init<\/code><\/td><td>Initialize the <code>cloud<\/code> block and connect the working directory<\/td><\/tr><tr><td>9<\/td><td>Migrate existing state to Cloud<\/td><td><code>terraform init -migrate-state<\/code><\/td><td>Migrate state from an existing backend to HCP Terraform<\/td><\/tr><tr><td>10<\/td><td>List connected Cloud workspaces<\/td><td><code>terraform workspace list<\/code><\/td><td>List workspaces mapped by the current cloud configuration<\/td><\/tr><tr><td>11<\/td><td>Show selected Cloud workspace<\/td><td><code>terraform workspace show<\/code><\/td><td>Identify the active workspace<\/td><\/tr><tr><td>12<\/td><td>Switch to Dev workspace<\/td><td><code>terraform workspace select proezi_dev<\/code><\/td><td>Select Dev when using a tag-based workspace configuration<\/td><\/tr><tr><td>13<\/td><td>Switch to Stage workspace<\/td><td><code>terraform workspace select proezi_stage<\/code><\/td><td>Select Stage when using a tag-based configuration<\/td><\/tr><tr><td>14<\/td><td>Switch to Prod workspace<\/td><td><code>terraform workspace select proezi_prod<\/code><\/td><td>Select Prod when using a tag-based configuration<\/td><\/tr><tr><td>15<\/td><td>Trigger remote Cloud plan<\/td><td><code>terraform plan<\/code><\/td><td>Execute a speculative plan in HCP Terraform<\/td><\/tr><tr><td>16<\/td><td>Trigger remote Cloud apply<\/td><td><code>terraform apply<\/code><\/td><td>Start a remote plan\/apply run in a CLI-driven workspace<\/td><\/tr><tr><td>17<\/td><td>Save remote Cloud plan<\/td><td><code>terraform plan -out=cloud.tfplan<\/code><\/td><td>Save a remote run for later review and approval<\/td><\/tr><tr><td>18<\/td><td>Inspect remote Cloud plan<\/td><td><code>terraform show cloud.tfplan<\/code><\/td><td>Review the saved remote plan<\/td><\/tr><tr><td>19<\/td><td>Apply saved remote plan<\/td><td><code>terraform apply cloud.tfplan<\/code><\/td><td>Apply the saved run in its originating workspace<\/td><\/tr><tr><td>20<\/td><td>Inspect Cloud remote state<\/td><td><code>terraform state list<\/code><\/td><td>List resources tracked in HCP Terraform state<\/td><\/tr><tr><td>21<\/td><td>Download Cloud remote state<\/td><td><code>terraform state pull<\/code><\/td><td>Retrieve the workspace&#8217;s current state document<\/td><\/tr><tr><td>22<\/td><td>Read Cloud outputs<\/td><td><code>terraform output<\/code><\/td><td>Read output values from the connected HCP workspace<\/td><\/tr><tr><td>23<\/td><td>Trigger remote destroy<\/td><td><code>terraform destroy<\/code><\/td><td>Destroy tracked infrastructure in a CLI-driven workspace; destructive<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Beginner \u2192 Advanced | Practical Examples | Hands-on Labs | Real Organization &amp; Workspaces | Updated October 2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide explains how to operate HCP Terraform (formerly Terraform Cloud) from the command line, using your actual organization and workspace names.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You&#8217;ll learn how to authenticate, connect Terraform code to cloud workspaces, execute plans and applies, manage variables, inspect remote state, troubleshoot failures, and automate Terraform operations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Your HCP Terraform environment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Organization: <a href=\"https:\/\/app.terraform.io\/app\/motoshare\">motoshare<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"739\" height=\"213\" src=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-3.png\" alt=\"\" class=\"wp-image-1246\" srcset=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-3.png 739w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-3-300x86.png 300w\" sizes=\"auto, (max-width: 739px) 100vw, 739px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These are the workspace names you supplied. I have not inspected their private settings or state, so the examples will distinguish configuration assumptions from confirmed details.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Understand Terraform CLI vs Terraform Cloud API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is the most important distinction.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Interface<\/th><th>Purpose<\/th><th>Example<\/th><\/tr><tr><td>Terraform CLI<\/td><td>Plan, apply, validate, and manage infrastructure<\/td><td><code>terraform plan<\/code><\/td><\/tr><tr><td>HCP Terraform CLI-driven workflow<\/td><td>Execute Terraform CLI operations using an HCP Terraform workspace<\/td><td><code>terraform apply<\/code> with a <code>cloud<\/code> block<\/td><\/tr><tr><td>HCP Terraform REST API<\/td><td>Manage organizations, projects, workspaces, variables, and runs programmatically<\/td><td><code>curl ...\/api\/v2\/...<\/code><\/td><\/tr><tr><td>HCP Terraform UI<\/td><td>Configure workspaces, teams, permissions, variables, and review runs<\/td><td><code>app.terraform.io<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">There is no general built-in <code>terraform cloud<\/code> command that administers every HCP Terraform resource. You use the normal Terraform CLI for infrastructure, and the API or the <code>hashicorp\/tfe<\/code> provider for broader platform administration.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"738\" height=\"350\" src=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-4.png\" alt=\"\" class=\"wp-image-1247\" srcset=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-4.png 738w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-4-300x142.png 300w\" sizes=\"auto, (max-width: 738px) 100vw, 738px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">With Remote Execution, plans and applies run on HCP Terraform workers, and the results stream to your terminal. With Local Execution, Terraform runs on your computer while HCP Terraform stores the state.<\/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<p class=\"wp-block-paragraph\">+1<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Prerequisites and installation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You&#8217;ll need Terraform CLI, an HCP Terraform account with access to <code>motoshare<\/code>, and a terminal. For API demonstrations, install <code>curl<\/code> and <code>jq<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.1 Install Terraform CLI on macOS<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>brew tap hashicorp\/tap\nbrew install hashicorp\/tap\/terraform<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the installation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform version<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To explore the commands available in your installed version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform -help\nterraform init -help\nterraform plan -help\nterraform workspace -help<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Usage: The <code>-help<\/code> option is especially useful because command flags and features can change between Terraform versions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.2 Log in to Terraform Cloud<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform login<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can also specify the hostname:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform login app.terraform.io<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform opens an authentication flow for creating and saving an HCP Terraform user token.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After logging in, the CLI can access workspaces your identity is authorized to use.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.3 Where are credentials stored?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On macOS and Linux, the default login credentials are stored at:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~\/.terraform.d\/credentials.tfrc.json<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The token is stored as readable text, so protect that file and never commit it to Git.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To remove locally stored login credentials:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform logout<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This removes the local credential but does not revoke the token on the server.<\/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<p class=\"wp-block-paragraph\">+1<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.4 Authenticate in CI\/CD without interactive login<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a CI\/CD job, you can provide the token through a protected environment variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export TF_TOKEN_app_terraform_io=\"$TFC_TOKEN\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, <code>TFC_TOKEN<\/code> represents a token securely injected into the job by your CI secrets manager.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Avoid hardcoding the token in Terraform files, shell scripts, or GitHub repositories.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Connect your Terraform CLI to an existing workspace<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We&#8217;ll use your <code>proezi_dev<\/code> workspace for this example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a working directory<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p ~\/terraform-training\/proezi-dev\ncd ~\/terraform-training\/proezi-dev<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create <code>cloud.tf<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform {\n  required_version = \"&gt;= 1.6.0\"\n\n  cloud {\n    organization = \"motoshare\"\n\n    workspaces {\n      name    = \"proezi_dev\"\n      project = \"proezi\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What each setting does:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Setting<\/th><th>Purpose<\/th><\/tr><tr><td><code>required_version<\/code><\/td><td>Enforces Terraform CLI version compatibility<\/td><\/tr><tr><td><code>cloud<\/code><\/td><td>Enables HCP Terraform integration<\/td><\/tr><tr><td><code>organization<\/code><\/td><td>Selects the <code>motoshare<\/code> organization<\/td><\/tr><tr><td><code>workspaces.name<\/code><\/td><td>Targets <code>proezi_dev<\/code><\/td><\/tr><tr><td><code>workspaces.project<\/code><\/td><td>Associates the workspace with project <code>proezi<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You don&#8217;t need to configure a separate <code>backend \"remote\"<\/code> block when using <code>cloud<\/code>. Terraform does not allow both together.<\/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\">Step 3: Initialize<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform init<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This connects the working directory to your HCP Terraform workspace, initializes providers and modules as needed, and prepares the state backend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Typical successful output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Initializing HCP Terraform...\n\nHCP Terraform has been successfully initialized!\n\nTerraform has been successfully initialized!<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Inspect existing infrastructure state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These are read-only commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state list\nterraform output<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first command lists resource addresses recorded in the workspace state. The second displays root-module output values, if any.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Important: Do not run <code>terraform plan<\/code>, <code>terraform apply<\/code>, or <code>terraform destroy<\/code> against this empty example directory if <code>proezi_dev<\/code> already manages real infrastructure. Missing resource definitions could cause Terraform to propose destroying existing resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This section is only for establishing connectivity and inspecting state.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Hands-on lab \u2014 Your first CLI-driven Terraform Cloud run<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For actual experimentation, I recommend creating a separate workspace, <code>proezi_cli_lab<\/code>, inside the <code>proezi<\/code> project. This keeps your real Dev, Stage, and Prod infrastructure untouched.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The exercise uses Terraform&#8217;s built-in <code>terraform_data<\/code> resource, so it doesn&#8217;t require AWS, Azure, or other cloud provider credentials and won&#8217;t provision external infrastructure.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.1 Prepare the lab directory<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p ~\/terraform-training\/proezi-cli-lab\ncd ~\/terraform-training\/proezi-cli-lab<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create these files:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>proezi-cli-lab\/\n\u251c\u2500\u2500 cloud.tf\n\u251c\u2500\u2500 variables.tf\n\u251c\u2500\u2500 main.tf\n\u251c\u2500\u2500 outputs.tf\n\u2514\u2500\u2500 lab.auto.tfvars<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5.2 File 1 \u2014 <code>cloud.tf<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform {\n  required_version = \"&gt;= 1.6.0\"\n\n  cloud {\n    organization = \"motoshare\"\n\n    workspaces {\n      name    = \"proezi_cli_lab\"\n      project = \"proezi\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When <code>terraform init<\/code> encounters a named workspace that doesn&#8217;t exist, it can create the workspace automatically, subject to your permissions. Verify the new workspace&#8217;s settings before its first run.<\/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\">5.3 File 2 \u2014 <code>variables.tf<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>variable \"app_name\" {\n  description = \"Application name\"\n  type        = string\n  default     = \"proezi\"\n}\n\nvariable \"environment\" {\n  description = \"Deployment environment\"\n  type        = string\n  default     = \"lab\"\n}\n\nvariable \"replicas\" {\n  description = \"Desired replica count\"\n  type        = number\n  default     = 1\n\n  validation {\n    condition     = var.replicas &gt;= 1\n    error_message = \"Replicas must be at least 1.\"\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5.4 File 3 \u2014 <code>main.tf<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>resource \"terraform_data\" \"application\" {\n  input = {\n    name        = var.app_name\n    environment = var.environment\n    replicas    = var.replicas\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>terraform_data<\/code> is useful for learning Terraform operations without provisioning a real virtual machine, network, or database.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.5 File 4 \u2014 <code>outputs.tf<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>output \"application_details\" {\n  description = \"Application configuration\"\n\n  value = terraform_data.application.output\n}\n\noutput \"environment_name\" {\n  value = var.environment\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5.6 File 5 \u2014 <code>lab.auto.tfvars<\/code><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>app_name    = \"proezi\"\nenvironment = \"lab\"\nreplicas    = 2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform automatically loads files ending in <code>.auto.tfvars<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.7 Execute the full CLI workflow<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"726\" height=\"422\" src=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-5.png\" alt=\"\" class=\"wp-image-1248\" srcset=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-5.png 726w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-5-300x174.png 300w\" sizes=\"auto, (max-width: 726px) 100vw, 726px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Run the commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform init\n\nterraform fmt\n\nterraform validate\n\nterraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since this is a new lab workspace, the plan should propose creating one <code>terraform_data.application<\/code> resource, assuming no existing lab state or policies prevent the run.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Apply the configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform apply<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Review the plan and type:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>yes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The apply runs in HCP Terraform when the workspace uses Remote Execution. You can view its history in:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/app.terraform.io\/app\/motoshare\/workspaces\/proezi_cli_lab\">Open proezi_cli_lab<\/a>This link targets the proposed lab workspace, which will exist only after you create it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now inspect the output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform output\nterraform output environment_name\nterraform output -json<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected <code>environment_name<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"lab\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5.8 Update a variable and rerun<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Edit <code>lab.auto.tfvars<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>replicas = 3<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan\nterraform apply<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform should show an in-place change to the lab&#8217;s stored data resource, rather than creating real servers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Learning outcome: You&#8217;ve completed a CLI-driven remote run, created state in HCP Terraform, updated configuration, and inspected outputs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Master Terraform CLI command reference<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The commands below work in ordinary Terraform configurations. When you connect a directory to HCP Terraform, their behavior depends on the workspace&#8217;s execution mode and workflow settings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 Setup, authentication, and initialization<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Example<\/th><th>Usage<\/th><\/tr><tr><td><code>version<\/code><\/td><td><code>terraform version<\/code><\/td><td>Display CLI and provider versions<\/td><\/tr><tr><td><code>-help<\/code><\/td><td><code>terraform plan -help<\/code><\/td><td>Show options and syntax<\/td><\/tr><tr><td><code>login<\/code><\/td><td><code>terraform login<\/code><\/td><td>Authenticate with HCP Terraform<\/td><\/tr><tr><td><code>logout<\/code><\/td><td><code>terraform logout<\/code><\/td><td>Remove local authentication token<\/td><\/tr><tr><td><code>init<\/code><\/td><td><code>terraform init<\/code><\/td><td>Initialize providers, modules, and cloud connection<\/td><\/tr><tr><td><code>init -upgrade<\/code><\/td><td><code>terraform init -upgrade<\/code><\/td><td>Upgrade selected providers\/modules within configured constraints<\/td><\/tr><tr><td><code>init -reconfigure<\/code><\/td><td><code>terraform init -reconfigure<\/code><\/td><td>Reconfigure backend or cloud connection without attempting state migration<\/td><\/tr><tr><td><code>init -migrate-state<\/code><\/td><td><code>terraform init -migrate-state<\/code><\/td><td>Migrate existing state when intentionally changing its storage configuration<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>-migrate-state<\/code> only after reviewing the source and destination state and taking appropriate backups.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.2 Code validation and planning<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Example<\/th><th>Usage<\/th><\/tr><tr><td><code>fmt<\/code><\/td><td><code>terraform fmt<\/code><\/td><td>Format HCL files<\/td><\/tr><tr><td><code>fmt -check<\/code><\/td><td><code>terraform fmt -check -recursive<\/code><\/td><td>Check formatting without rewriting files<\/td><\/tr><tr><td><code>validate<\/code><\/td><td><code>terraform validate<\/code><\/td><td>Verify configuration syntax and structural validity<\/td><\/tr><tr><td><code>plan<\/code><\/td><td><code>terraform plan<\/code><\/td><td>Preview infrastructure changes<\/td><\/tr><tr><td><code>plan -var<\/code><\/td><td><code>terraform plan -var='replicas=3'<\/code><\/td><td>Supply a run-specific Terraform variable<\/td><\/tr><tr><td><code>plan -var-file<\/code><\/td><td><code>terraform plan -var-file=dev.tfvars<\/code><\/td><td>Load variable values from a selected file<\/td><\/tr><tr><td><code>plan -out<\/code><\/td><td><code>terraform plan -out=review.tfplan<\/code><\/td><td>Save a plan for later inspection\/apply<\/td><\/tr><tr><td><code>plan -detailed-exitcode<\/code><\/td><td><code>terraform plan -detailed-exitcode<\/code><\/td><td>Indicate whether changes are needed via exit status<\/td><\/tr><tr><td><code>plan -refresh-only<\/code><\/td><td><code>terraform plan -refresh-only<\/code><\/td><td>Inspect state updates based on real infrastructure<\/td><\/tr><tr><td><code>plan -replace<\/code><\/td><td><code>terraform plan -replace=aws_instance.web<\/code><\/td><td>Preview replacement of a specific resource<\/td><\/tr><tr><td><code>plan -target<\/code><\/td><td><code>terraform plan -target=aws_instance.web<\/code><\/td><td>Target a resource for exceptional recovery or repair<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><code>-target<\/code> and <code>-replace<\/code> are not normal deployment practices. Use them only when their behavior is understood and justified.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.3 Applying and managing infrastructure<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Example<\/th><th>Usage<\/th><\/tr><tr><td><code>apply<\/code><\/td><td><code>terraform apply<\/code><\/td><td>Plan and apply changes<\/td><\/tr><tr><td><code>apply -auto-approve<\/code><\/td><td><code>terraform apply -auto-approve<\/code><\/td><td>Skip interactive approval; suitable only for properly controlled automation<\/td><\/tr><tr><td><code>apply FILE<\/code><\/td><td><code>terraform apply review.tfplan<\/code><\/td><td>Apply a previously saved plan<\/td><\/tr><tr><td><code>apply -refresh-only<\/code><\/td><td><code>terraform apply -refresh-only<\/code><\/td><td>Update state and outputs without normal infrastructure reconciliation<\/td><\/tr><tr><td><code>destroy<\/code><\/td><td><code>terraform destroy<\/code><\/td><td>Destroy all resources managed by the selected configuration\/state<\/td><\/tr><tr><td><code>destroy -target<\/code><\/td><td><code>terraform destroy -target=aws_instance.web<\/code><\/td><td>Target a subset for destruction; exceptional use only<\/td><\/tr><tr><td><code>show<\/code><\/td><td><code>terraform show<\/code><\/td><td>Display state information<\/td><\/tr><tr><td><code>show FILE<\/code><\/td><td><code>terraform show review.tfplan<\/code><\/td><td>Display the contents of a saved plan<\/td><\/tr><tr><td><code>output<\/code><\/td><td><code>terraform output<\/code><\/td><td>Show root-module output values<\/td><\/tr><tr><td><code>output -json<\/code><\/td><td><code>terraform output -json<\/code><\/td><td>Export output values in JSON<\/td><\/tr><tr><td><code>output -raw<\/code><\/td><td><code>terraform output -raw environment_name<\/code><\/td><td>Get a string output without quotes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">6.4 Terraform state operations<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Example<\/th><th>Usage<\/th><\/tr><tr><td><code>state list<\/code><\/td><td><code>terraform state list<\/code><\/td><td>List tracked resources<\/td><\/tr><tr><td><code>state show<\/code><\/td><td><code>terraform state show terraform_data.application<\/code><\/td><td>Inspect one tracked resource<\/td><\/tr><tr><td><code>state pull<\/code><\/td><td><code>terraform state pull<\/code><\/td><td>Retrieve the current state document<\/td><\/tr><tr><td><code>state mv<\/code><\/td><td><code>terraform state mv OLD NEW<\/code><\/td><td>Change a resource address in state<\/td><\/tr><tr><td><code>state rm<\/code><\/td><td><code>terraform state rm ADDRESS<\/code><\/td><td>Stop tracking a resource without deleting it<\/td><\/tr><tr><td><code>state replace-provider<\/code><\/td><td><code>terraform state replace-provider OLD NEW<\/code><\/td><td>Change provider addresses stored in state<\/td><\/tr><tr><td><code>import<\/code><\/td><td><code>terraform import ADDRESS ID<\/code><\/td><td>Bring an existing remote resource under Terraform state management<\/td><\/tr><tr><td><code>force-unlock<\/code><\/td><td><code>terraform force-unlock LOCK_ID<\/code><\/td><td>Manually release a state lock where supported by the backend<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">State-changing commands require special care because incorrect changes can cause future Terraform plans to replace or destroy infrastructure. Terraform state subcommands support remote state, and state modification commands write local backups.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.5 Workspaces, modules, testing, and debugging<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Command<\/th><th>Example<\/th><th>Usage<\/th><\/tr><tr><td><code>workspace list<\/code><\/td><td><code>terraform workspace list<\/code><\/td><td>List workspaces available through the configuration<\/td><\/tr><tr><td><code>workspace select<\/code><\/td><td><code>terraform workspace select proezi_dev<\/code><\/td><td>Select a different workspace, when supported<\/td><\/tr><tr><td><code>workspace show<\/code><\/td><td><code>terraform workspace show<\/code><\/td><td>Display the selected CLI workspace<\/td><\/tr><tr><td><code>workspace new<\/code><\/td><td><code>terraform workspace new demo<\/code><\/td><td>Create a workspace, where supported<\/td><\/tr><tr><td><code>workspace delete<\/code><\/td><td><code>terraform workspace delete demo<\/code><\/td><td>Delete an eligible workspace; destructive administrative action<\/td><\/tr><tr><td><code>providers<\/code><\/td><td><code>terraform providers<\/code><\/td><td>Display required provider dependencies<\/td><\/tr><tr><td><code>get<\/code><\/td><td><code>terraform get<\/code><\/td><td>Download modules; generally prefer <code>terraform init<\/code><\/td><\/tr><tr><td><code>console<\/code><\/td><td><code>terraform console<\/code><\/td><td>Interactively test HCL expressions<\/td><\/tr><tr><td><code>graph<\/code><\/td><td><code>terraform graph<\/code><\/td><td>Generate dependency-graph output<\/td><\/tr><tr><td><code>test<\/code><\/td><td><code>terraform test<\/code><\/td><td>Execute Terraform test files<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Important workspace limitation: <code>terraform workspace select<\/code> is not the way to switch between workspaces when your <code>cloud<\/code> block specifies a fixed <code>workspaces.name<\/code>. Section 9 explains supported workspace-selection methods.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Planning and applying \u2014 Detailed examples<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These exercises use the separate <code>proezi_cli_lab<\/code> workspace created in Section 5.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.1 Example: Standard remote plan<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When to use: Before every infrastructure change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With a remote-execution workspace, this creates a speculative plan using your local Terraform files and the remote workspace context.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A speculative plan can show potential changes, but cannot subsequently be applied directly.<\/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\">7.2 Example: Pass a variable directly<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -var=\"replicas=4\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When to use: Temporarily override a Terraform input variable for a single run.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The CLI value does not permanently change the stored workspace variable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.3 Example: Use an explicit variable file<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>dev.tfvars<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app_name    = \"proezi\"\nenvironment = \"development\"\nreplicas    = 2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Execute:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -var-file=\"dev.tfvars\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When to use: You want reusable environment-specific values without hardcoding everything into <code>.tf<\/code> resources.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.4 Example: Check if a deployment is needed<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -detailed-exitcode\necho $?<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Exit codes:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Code<\/th><th>Meaning<\/th><\/tr><tr><td><code>0<\/code><\/td><td>Plan succeeded; no changes<\/td><\/tr><tr><td><code>1<\/code><\/td><td>An error occurred<\/td><\/tr><tr><td><code>2<\/code><\/td><td>Plan succeeded; changes are proposed<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This is helpful in CI\/CD pipelines that need to distinguish infrastructure drift or new changes from errors.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.5 Example: Save, review, and apply a plan<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -out=review.tfplan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inspect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform show review.tfplan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apply:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform apply review.tfplan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For remote CLI-driven runs, this requires Terraform CLI 1.6 or later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HCP Terraform&#8217;s remote saved-plan file is a reference to a remote run, not an ordinary local binary plan. It can only be applied in the originating remote workspace, and it becomes stale if the underlying state is no longer valid.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.6 Example: Use automation approval<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform apply -auto-approve<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When to use: Only in approved automation where plan review, change controls, and workspace permissions are already established.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not use this as a shortcut for deploying into <code>proezi_prod<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.7 Example: Inspect a plan in JSON<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a remote saved plan:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform show -json review.tfplan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike the human-readable plan, JSON can contain sensitive values in unredacted form. HCP Terraform requires workspace admin permission to inspect a remote saved plan in JSON. Store such output securely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.8 Example: Refresh state<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -refresh-only<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This previews how state would change to reflect infrastructure modified outside Terraform.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To commit a refresh-only operation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform apply -refresh-only<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This does not perform ordinary desired-state reconciliation. It updates Terraform&#8217;s recorded view of existing infrastructure and outputs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Terraform Cloud variables through CLI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">HCP Terraform variables are especially important because they can be defined at multiple scopes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8.1 Common ways to provide variable values<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Method<\/th><th>Example<\/th><th>Where the value comes from<\/th><\/tr><tr><td>Variable default<\/td><td><code>default = 2<\/code><\/td><td>Terraform configuration<\/td><\/tr><tr><td>Automatic <code>.tfvars<\/code><\/td><td><code>lab.auto.tfvars<\/code><\/td><td>Configuration files<\/td><\/tr><tr><td>Explicit <code>.tfvars<\/code><\/td><td><code>-var-file=dev.tfvars<\/code><\/td><td>Command line<\/td><\/tr><tr><td>CLI argument<\/td><td><code>-var='replicas=4'<\/code><\/td><td>Command line<\/td><\/tr><tr><td>Local shell<\/td><td><code>TF_VAR_replicas=4<\/code><\/td><td>Your terminal<\/td><\/tr><tr><td>Workspace Terraform variable<\/td><td><code>replicas = 2<\/code><\/td><td>HCP workspace settings<\/td><\/tr><tr><td>Project variable set<\/td><td>Shared application settings<\/td><td>HCP project<\/td><\/tr><tr><td>Organization variable set<\/td><td>Shared settings across projects<\/td><td>HCP organization<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">8.2 Example: Local environment variable<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>export TF_VAR_replicas=5\n\nterraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Remove it after the test:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset TF_VAR_replicas<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">8.3 Example: Store the value in HCP Terraform<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Open:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/app.terraform.io\/app\/motoshare\/workspaces\/proezi_dev\/variables\">proezi_dev \u2192 Variables<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a Terraform variable:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Key<\/th><th>Value<\/th><th>Category<\/th><\/tr><tr><td><code>environment<\/code><\/td><td><code>development<\/code><\/td><td>Terraform<\/td><\/tr><tr><td><code>replicas<\/code><\/td><td><code>2<\/code><\/td><td>Terraform<\/td><\/tr><tr><td><code>app_name<\/code><\/td><td><code>proezi<\/code><\/td><td>Terraform<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">These are illustrative values, not changes I&#8217;ve made. Only add keys actually declared in the Terraform configuration used by that workspace.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For <code>proezi_stage<\/code>, you might set <code>environment = staging<\/code>; for <code>proezi_prod<\/code>, <code>environment = production<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Workspace variables are persistent and apply to the workspace&#8217;s runs unless overridden by a higher-precedence source.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8.4 Variable precedence in remote CLI runs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The practical precedence, highest first, is:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"728\" height=\"473\" src=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-6.png\" alt=\"\" class=\"wp-image-1249\" srcset=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-6.png 728w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/10\/image-6-300x195.png 300w\" sizes=\"auto, (max-width: 728px) 100vw, 728px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is a simplified grouping. Within priority and ordinary variable sets, HCP Terraform also applies rules for set ownership, scope, and lexical order of set names.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, suppose:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>lab.auto.tfvars<\/code> sets <code>replicas = 2<\/code><\/li>\n\n\n\n<li>Your HCP workspace sets <code>replicas = 3<\/code><\/li>\n\n\n\n<li>You execute <code>terraform plan -var='replicas=6'<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The plan uses 6, unless a priority variable set enforces a different value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Important distinction: <code>TF_VAR_replicas<\/code> is a Terraform input variable. <code>AWS_ACCESS_KEY_ID<\/code>, <code>AWS_SECRET_ACCESS_KEY<\/code>, and similar provider environment variables are a separate category. With remote execution, provider credentials generally need to be available in the HCP remote run environment, not merely on your laptop. Prefer short-lived, dynamic provider credentials where possible.<\/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. Managing Dev, Stage, and Prod workspaces<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This section directly addresses your three workspaces:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>proezi_dev<\/code><\/li>\n\n\n\n<li><code>proezi_stage<\/code><\/li>\n\n\n\n<li><code>proezi_prod<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">There are three useful ways to target them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method A \u2014 Separate Terraform directories<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Recommended for straightforward environment isolation<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform\/\n\u251c\u2500\u2500 dev\/\n\u2502   \u2514\u2500\u2500 cloud.tf\n\u251c\u2500\u2500 stage\/\n\u2502   \u2514\u2500\u2500 cloud.tf\n\u2514\u2500\u2500 prod\/\n    \u2514\u2500\u2500 cloud.tf<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Each directory contains its own configuration for the correct HCP workspace.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Dev:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform {\n  cloud {\n    organization = \"motoshare\"\n\n    workspaces {\n      name    = \"proezi_dev\"\n      project = \"proezi\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For Stage, use <code>name = \"proezi_stage\"<\/code>. For Prod, use <code>name = \"proezi_prod\"<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can then execute commands from the repository root:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform -chdir=dev init\nterraform -chdir=dev plan\n\nterraform -chdir=stage init\nterraform -chdir=stage plan\n\nterraform -chdir=prod init\nterraform -chdir=prod plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is a clear mapping, but each directory must contain the intended complete configuration for its environment. Don&#8217;t create only a <code>cloud.tf<\/code> and then run <code>apply<\/code> against a workspace that already manages resources.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method B \u2014 Workspace selection using tags<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the three workspaces use the same Terraform configuration, you can choose them from one working directory using workspace tags.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, deliberately apply the same key-value tag to all three workspaces through the HCP Terraform UI:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>application = proezi<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then, using Terraform CLI 1.10 or later, configure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform {\n  cloud {\n    organization = \"motoshare\"\n\n    workspaces {\n      tags = {\n        application = \"proezi\"\n      }\n\n      project = \"proezi\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform init<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">List matching workspaces:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform workspace list<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Select Dev:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform workspace select proezi_dev<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm the selection:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform workspace show<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Switch to Stage:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform workspace select proezi_stage\nterraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Switch to Prod:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform workspace select proezi_prod\nterraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This requires each workspace to match the configured tags and project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Crucial: <code>workspaces.name<\/code> and <code>workspaces.tags<\/code> are mutually exclusive. You cannot use <code>terraform workspace select<\/code> to switch among several HCP workspaces when the configuration is bound to a single name.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method C \u2014 Workspace selection through an environment variable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For scripts that must target an existing workspace without hardcoding its name, you can omit the <code>workspaces<\/code> block:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform {\n  cloud {\n    organization = \"motoshare\"\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export TF_WORKSPACE=proezi_dev\n\nterraform init\nterraform plan<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The environment variable selects an existing HCP Terraform workspace. It does not automatically create a missing workspace in this configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To change the target in automation, supply a different <code>TF_WORKSPACE<\/code> value for a separately initialized job or working directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Production recommendation: Keep production targeting explicit, use separate pipeline approvals, and validate the selected workspace before any state-changing operation.<\/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. Remote state management \u2014 Hands-on examples<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform state records which infrastructure objects Terraform manages.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In HCP Terraform, state is stored centrally and can be shared by authorized users and automation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.1 List resources in remote state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">From an initialized workspace directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state list<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For the lab, an expected resource address is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform_data.application<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For a real AWS configuration, the output might look like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aws_vpc.main\naws_subnet.public\naws_security_group.web\naws_instance.web<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These AWS addresses are examples, not confirmed resources in your workspaces.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.2 Inspect one resource<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state show terraform_data.application<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Usage: Examine a resource&#8217;s recorded attributes without generating a new plan.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.3 Back up remote state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">From the isolated lab directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>umask 077\nterraform state pull &gt; lab-state-backup.tfstate<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Usage: Capture a state snapshot before maintenance or recovery exercises.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Never commit state backups to Git or share them casually. State may contain passwords, credentials, identifiers, and other sensitive values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.4 Move a resource address in state<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Command format:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state mv OLD_ADDRESS NEW_ADDRESS<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Illustration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state mv \\\n  terraform_data.application \\\n  terraform_data.proezi_application<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Usage: Rename a tracked resource address without creating a new infrastructure object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not execute this illustration without also updating the HCL resource declaration to match. A <code>moved<\/code> block in version-controlled configuration is generally preferable for planned refactoring.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.5 Remove a resource from state<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform state rm terraform_data.application<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Usage: Tell Terraform to forget an object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This does not destroy the underlying object. For a real cloud resource, it can leave infrastructure running and unmanaged, so this command is intentionally a reference example, not a recommended lab step.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.6 Import existing infrastructure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose an AWS S3 bucket already exists.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A conventional CLI import looks like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform import \\\n  aws_s3_bucket.existing \\\n  my-existing-bucket<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You must first declare the resource in Terraform configuration and provide a correctly configured AWS provider.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An important HCP-specific detail is that <code>terraform import<\/code> runs locally, even when plans and applies run remotely. Your local environment may therefore need access to provider credentials and the target infrastructure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>HCP Terraform Cloud \u2014 CLI Command Summary Organization: motoshare | Project: proezi # Cloud operation Command \/ Example Usage 1 Login to Terraform Cloud terraform login Authenticate&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1245","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1245"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1245\/revisions"}],"predecessor-version":[{"id":1253,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1245\/revisions\/1253"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}