cloud IaC terraform tfc claude-curated
Terraform Cloud (TFC, also branded HCP Terraform) is a strong product, but every managed service has rough edges that show up only after you’ve committed to it. This page collects the ones that have surprised teams in the past so a future evaluation can go in eyes-open. See Terraform Cloud Workspaces for the happy-path overview.
Cost scales with resources
Pricing is per managed resource per month. The “managed resource” count includes everything in state, not just the things you’d intuitively call expensive — every IAM role, every security group rule, every DNS record counts. A reasonable medium-size estate (one or two thousand resources, a handful of envs) is a few hundred dollars a month. A large one (tens of thousands of resources, dozens of envs) is well into five figures monthly, with reports of $5K+ at large shops being common.
Mitigations:
- Be deliberate about which resources are in TF and which can stay outside. Don’t import every DNS record if Route 53 is fine to manage outside TF.
- Consider Atlantis or DIY for low-traffic envs and TFC only for prod. See CI CD for Terraform for tool comparison.
- Track resource count growth. A surprising amount of growth comes from small modules instantiated many times (one IAM role per Lambda × 200 Lambdas).
Slow runs and queueing
TFC workers are shared across customers (on the standard tier). At peak times — start of the workday across timezones, after an outage — you can sit in the run queue for ten minutes before the plan starts. Not catastrophic, but enough to break flow.
Mitigations:
- Self-hosted agents move runs onto your own workers. Costs more, but predictable.
- Local execution mode (
execution_mode = local) bypasses TFC workers entirely; useful for fast iteration on a slow plan. See Terraform CLI with Cloud Hybrid.
Variable set precedence confusion
Variable sets are powerful but the precedence rules surprise people. The documented order is workspace > workspace-attached set > project set > org set, with -var flags overriding everything in CLI-driven runs.
What goes wrong:
- A sensitive variable defined in two places — you can’t read either to compare. Treat as a Cyber Security handling concern.
- The same key defined as both a Terraform variable and an environment variable. Each is in its own namespace, so they don’t override each other; the workspace ends up with both, and a confusing run.
- A variable set is detached from a workspace and the workspace inherits a different value silently — a form of Terraform State Drift in the configuration layer.
Treat the precedence as a contract, document where each shared variable is set, and avoid defining the same key in two scopes unless you mean it.
State migration when leaving TFC
State migration into TFC is well-supported (terraform login, change the backend, run terraform init -migrate-state). Migration out is less polished — moving to a self-hosted S3 + DynamoDB backend is the common path. You’re moving:
- The current state file, per workspace (you can pull this with
terraform state pull). - The history (state versions, run history, audit log) — there’s no first-class export.
- Variables, including sensitive ones (sensitive values are not readable via the API, so you re-enter them).
- Workspace settings (working directory, Terraform version, etc.).
For a handful of workspaces, this is a weekend. For hundreds, it’s a project. Plan the migration off TFC before you commit deeply, even if you’re sure you’ll stay.
API rate limits
The TFC API rate-limits aggressively. If you’re driving a lot of automation against it (creating workspaces programmatically, polling run status, syncing variables) you will hit 429s.
Mitigations:
- Cache where you can. Run state and workspace metadata don’t change second-by-second.
- Back off and retry with jitter. Don’t tight-loop polling.
- Batch updates where the API supports it.
A custom platform that wraps TFC for self-service workspace creation needs particular care here — a thundering herd of provisioning requests can exhaust the org’s rate budget.
VCS integration tokens
TFC connects to GitHub/GitLab/Bitbucket via OAuth. The token is held by TFC and used to read repos, post statuses, and trigger runs.
Operational issues:
- The token can expire or be revoked, breaking VCS-driven runs across many workspaces simultaneously.
- Rotation needs coordination — re-authorising the OAuth app is one click but can briefly take all VCS triggers offline.
- If the user who originally connected the integration leaves and their account is offboarded, the integration may break.
Mitigation: connect via a long-lived service account or a GitHub App rather than a personal account. Document the rotation procedure. Pair with Least Privilages on the linked account.
Workspace name limits and naming
TFC enforces a name format (lowercase, hyphens, limited length) and the names are immutable in some flows. A naming scheme that ages badly (my-cool-project-prod-eu-west-1-final) is hard to fix later because renaming a workspace can break VCS-trigger config and any external automation that references the name.
Pick a naming convention early. Keep it short. Build it around stable axes (env, region, service) rather than transient ones (release name, project codename).
Sentinel can fight you in subtle ways
Sentinel is TFC’s policy-as-code language. Powerful, but:
- Policies run on the run’s plan output. A subtle change to a provider’s plan format can cause a previously-passing policy to fail without anyone changing the policy.
- Soft-mandatory policies that “everyone overrides” gradually erode their own meaning.
- Debugging a Sentinel failure means reading the policy plus the plan JSON; the error messages aren’t always pointing at the actual root cause.
- Test coverage for policies is hard to maintain; OPA tooling is more mature in this regard.
Several teams have ended up replacing Sentinel with OPA for these reasons. TFC supports both.
Import blocks: provider coverage gaps
The declarative Terraform Import Block is great when it works. It depends on each resource implementing Importer, and not every resource type does. With a remote-execution workspace running on TFC’s workers, an import that fails halfway leaves state in a partially-imported condition — recovery requires CLI access to the backend, which is awkward when the backend is TFC.
Test imports first in a non-prod workspace. Have a recovery plan (the CLI workflow from Terraform CLI with Cloud Hybrid) ready before you import in prod.
Summary
None of these are reasons to avoid TFC outright; they’re reasons to enter the relationship knowing the failure modes. The pattern that holds across all of them: design for migration off, even while you’re using it. Keep config provider-portable, treat the state file as the boundary, and remember that any abstraction TFC adds on top — variable sets, projects, Sentinel policies — is yours to recreate elsewhere if you ever leave. Terragrunt is the typical destination. See also Cloudflare Terraform Provider Pitfalls for parallel non-AWS provider gotchas.