Terraform Cloud / HCP Backend
HCP Terraform (formerly Terraform Cloud) is HashiCorp’s managed service for storing state, coordinating locking, and executing Terraform runs on hosted infrastructure. Instead of wiring together an S3 bucket, a DynamoDB lock table, and a CI pipeline yourself, you point Terraform at an HCP workspace and get encrypted state, automatic locking, run history, policy enforcement, and a shared UI out of the box. It is the simplest way for a team to graduate from local state to a collaborative, auditable workflow.
The cloud block
Modern Terraform (1.1+) connects to HCP using a cloud block nested inside terraform. This replaces the older backend "remote" configuration and is the recommended approach for new projects. The block names your organization and selects one or more workspaces.
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
cloud {
organization = "devcraftly"
workspaces {
name = "networking-prod"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "prod-vpc"
}
}
Authenticate once with terraform login, which stores a user token in ~/.terraform.d/credentials.tfrc.json. Then run terraform init to bind the configuration to the workspace.
terraform login
terraform init
Output:
Initializing HCP Terraform...
Initializing provider plugins...
- Reinstalling hashicorp/aws v5.61.0...
HCP Terraform has been successfully initialized!
You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.
Tip: The
cloudblock cannot contain interpolations or variables — values must be static. To switch organizations or workspaces dynamically (for example in CI), pass-backend-configfiles or use theTF_CLOUD_ORGANIZATIONandTF_WORKSPACEenvironment variables.
Managed state and locking
Once initialized, HCP Terraform becomes the system of record for your state. Every apply writes a new encrypted state version to the workspace and retains the full version history, so you can inspect, download, or roll back to any prior state from the UI or API. There is no bucket to provision, no encryption to configure, and no separate lock table to maintain.
Locking is automatic and transparent. When a run starts, HCP places a lock on the workspace; concurrent runs queue instead of corrupting state. This is the same guarantee you would build manually with a DynamoDB table for the S3 backend, but without the extra resources.
Remote vs. local execution
A key decision per workspace is the execution mode. This controls where the plan and apply actually run.
| Execution mode | Where runs execute | State stored in HCP | Typical use |
|---|---|---|---|
| Remote | HCP-hosted agents | Yes | Team workflows, VCS-driven runs, policy gates |
| Local | Your machine / CI runner | Yes | Custom tooling, network-restricted providers |
| Agent | Self-hosted HCP agent | Yes | Private networks, on-prem targets |
In remote mode, terraform plan streams the run to HCP and shows the live output in your terminal while the work happens server-side — credentials and the run log stay in the platform. In local mode, only the state is remote; execution stays on your machine, which is handy when a provider needs access to a private network the HCP runners cannot reach.
terraform plan
Output:
Running plan in HCP Terraform. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.
Terraform v1.5.7
Initializing plugins and modules...
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ cidr_block = "10.0.0.0/16"
+ enable_dns_hostnames = true
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Workspaces
HCP workspaces are the unit of state isolation — each one holds its own state, variables, run history, and access controls. This differs from local CLI workspaces (which only switch state slices within a single backend). A common pattern is one HCP workspace per environment-and-component, such as networking-prod and networking-staging.
You can map several workspaces with a tags filter instead of a single name, letting one configuration target many environments:
terraform {
cloud {
organization = "devcraftly"
workspaces {
tags = ["networking"]
}
}
}
With tag-based selection, set the active workspace via TF_WORKSPACE or terraform workspace select. Sensitive inputs like AWS_ACCESS_KEY_ID are stored as workspace environment variables marked sensitive, so credentials never live in your VCS.
When a managed backend wins
A managed backend pays off as soon as more than one person touches the infrastructure. Compared to a DIY S3 + DynamoDB setup, HCP gives you run history, a UI, role-based access, VCS-triggered runs, and Sentinel/OPA policy checks without operating any of it. The trade-offs are cost beyond the free tier and dependence on a hosted control plane.
Note: OpenTofu does not support the HCP
cloudblock. If you use OpenTofu, configure theremotebackend against a compatible state service (HCP exposes a remote-backend-compatible API, and Scalr/Spacelift offer drop-in alternatives). For pure OpenTofu state hosting, the S3 backend with native locking is the common choice.
Best practices
- Use the
cloudblock rather than the legacybackend "remote"block for any Terraform 1.1+ project. - Keep one workspace per environment-and-component to bound the blast radius and enable least-privilege access.
- Store provider credentials as sensitive workspace variables, never in source control or the
cloudblock. - Prefer remote execution so runs, logs, and secrets stay in the platform and benefit from policy enforcement.
- Pin
required_versionand provider versions so HCP runners and local machines resolve identical plans. - Use VCS-driven workflows with speculative plans on pull requests to catch drift before merge.
- For OpenTofu, plan for a remote-backend-compatible service since the
cloudblock is unsupported.