Terraform Cloud Migration Playbook: A 30/60/90-Day Plan for Enterprise Teams

By Firefly
This playbook walks enterprise teams through a 90-day Terraform Cloud migration: assessing current usage, migrating state and backends, moving Sentinel policies to OPA/Rego, and cutting over safely—using parallel operation and predefined rollback criteria to avoid state divergence and policy gaps.
Terraform
Cloud governance
Multi-cloud
Cloud asset management
DevOps

In this article

Terraform Cloud migration strategy for enterprise infrastructure and DevOps teams

TL;DR

  • A Terraform Cloud migration has two things that can go quietly wrong if rushed: state divergence between the old and new backend, and a policy enforcement gap the moment Sentinel gets turned off before its OPA/Rego replacement is actually proven.
  • The safe path runs on two overlapping mechanisms through every phase: parallel operation (old and new platform both active at once) and rollback criteria defined in advance, not improvised mid-incident.
  • The playbook breaks into four phases: Assessment (week 1-2), state and backend migration (days 1-30), policy migration (days 15-45, overlapping state work), and cutover (days 45-90).
  • Every phase has a minimum retention or parallel-run window built in: 2 weeks of read-only access to the old state backend, 2 weeks of policies running in alert-only mode before enforcement, and 30 days of TFC workspace retention post-cutover; these aren't padding, they're what catches a problem before it's irreversible.
  • Firefly isn't just a migration destination here; its inventory, drift detection, and Guardrails engine map directly onto specific checklist items in every phase, from establishing a baseline in Phase 0 to validating cutover in Phase 3.

Getting Started: The Basics of a Terraform Cloud Migration

A Terraform Cloud migration means moving three things off HCP Terraform or Terraform Enterprise onto a different platform: the state files that track what's actually deployed, the policy enforcement that governs what's allowed to deploy, and the workspaces and pipelines that tie the two together. It's not like migrating an application to a new host, where a bad migration usually just means recoverable downtime. A bad state migration means losing track of what's actually deployed, two backends disagreeing about which resources exist, or a policy engine going dark for the exact window nobody's watching closely enough to notice.

Two things go wrong specifically when this gets rushed: state divergence, where the old and new backend both briefly think they're the source of truth and a terraform apply against either one silently overwrites the other's understanding of reality, and a policy gap, where Sentinel and its OPA/Rego replacement are never functionally identical on day one, so disabling one before the other's proven leaves a window with no enforcement at all. The fix for both is the same pattern repeated across every phase ahead: run old and new in parallel before cutting over, and decide rollback criteria in advance rather than mid-incident, which is why this piece breaks the move into four phases across a 90-day window instead of a weekend cutover.

Before You Start: What Choosing a Target Actually Requires

This playbook assumes a target platform is already picked, whether that's a managed Terraform-only backend like Scalr or Spacelift, a self-hosted GitOps setup like Atlantis, a multi-IaC lifecycle platform like env0, or a governance and inventory layer like Firefly. That decision depends on questions this playbook doesn't cover in depth: IaC tool mix, execution model, pricing predictability, and governance scope, which are broken down in Best Terraform Cloud Alternatives in 2026. What follows here starts from the point where that decision has already been made, and focuses entirely on executing the move safely.

90-day Terraform Cloud migration timeline showing assessment, migration, policy, and cutover phases

Phase 0: Assessment (Week 1-2)

Inventory your current TFC/TFE usage:

  • How many workspaces do you have? Categorize by team, environment, and change frequency.
  • Where is state stored: TFC-managed backend, or remote backends (S3/GCS/Azure Blob)?
  • Which Sentinel or OPA policies are active? Document each rule, enforcement level, and what it blocks.
  • What VCS integrations are in use (GitHub, GitLab, Azure DevOps)?
  • What notification and alerting hooks exist?
  • Are you using Terraform Cloud Agents for private network access?
  • What secrets and variable sets need to be migrated?

This step is easy to underestimate. A team that thinks it has "about 40 workspaces" frequently finds closer to 60 once workspaces created for one-off testing or abandoned proofs of concept get counted, and every one of those needs a decision (migrate, archive, or delete) before Phase 1 starts, not during it.

Terraform Cloud migration Phase 0 assessment checklist for inventory, policies, and infrastructure

Choose your target category:

  • Terraform/OpenTofu only, want a managed backend: Scalr or Spacelift
  • GitOps PR automation, self-hosted: Atlantis
  • Multi-IaC plus lifecycle/FinOps: env0
  • Unified inventory, governance across tools, and drift detection: Firefly

Where Firefly fits in Phase 0 specifically: the workspace inventory above is manual by design; someone has to count and categorize. Firefly's Cloud Asset Inventory can run alongside that manual pass and produce an independent baseline: connect it read-only to the same cloud accounts TFC manages, and it surfaces every resource tagged by IaC status (Codified, Drifted, or Unmanaged) regardless of whether a human remembered it exists. That baseline number, what percentage of the environment is actually codified today, is worth capturing before migration starts, since it's the number a team should be able to point to improving by day 90, not just "we moved platforms."

Infrastructure inventory dashboard showing resources and migration data during Terraform Cloud migration

Phase 1: State and Backend Migration (Days 1-30)

State migration checklist:

  • Pull current state files: terraform state pull > backup.tfstate for each workspace
  • Decide on state destination: managed backend (new platform) vs. BYO (S3 + DynamoDB, Azure Blob + Table, GCS)
  • Update backend configuration in .tf files for the target backend
  • Run terraform init -migrate-state or terraform init -reconfigure in each workspace
  • Validate state by running terraform plan and confirming zero unexpected changes
  • Enable state locking on the new backend before any team members switch
  • Retain the TFC workspace in read-only mode for rollback during a validation period of at least two weeks

For detailed backend migration mechanics, the Terraform state management guide covers locking, versioning, and backend transitions.

The two-week read-only retention step is the one teams most often skip under time pressure, and it's the one worth protecting above the others. Consider a workspace with a database resource that has a prevent_destroy lifecycle rule. If the state migration subtly drops that lifecycle block during backend reconfiguration, a terraform plan immediately after migration can still come back clean, since the plan comparison only checks against the new state, not against what the resource actually depended on before. The gap doesn't surface until someone runs an apply that would have hit the missing safeguard, which might be weeks later.

Where Firefly fits in Phase 1 specifically: the terraform plan validation step above has a structural blind spot; it only compares the new state file against the .tf configuration, not against what's actually running in the cloud. If the migration itself introduced a subtle drift (a tag lost, a lifecycle rule dropped, an attribute silently changed during backend reconfiguration), a clean terraform plan won't catch it, because it isn't checking live provider state at all. Firefly's drift detection does check against live state, so running an inventory scan immediately after each workspace migrates is a second, independent validation layer on top of terraform plan, catching exactly the class of error a plan-only check structurally can't see. Firefly also supports both state destinations in the checklist above natively, BYO S3/Azure Blob/GCS or Firefly-managed, so state ownership doesn't have to change again later if the target platform changes.

A Guardrail check confirming state locking is actually enabled on the new backend, closing the loop on that checklist item automatically rather than trusting it got done manually, looks like this in Firefly's policy schema:

package Cx

import data.generic.terraform as tf_lib

CxPolicy[result] {
	resource := input.document[i].resource.aws_dynamodb_table[name]
	not resource.point_in_time_recovery

	result := {
		"documentId": input.document[i].id,
		"resourceType": "aws_dynamodb_table",
		"resourceName": tf_lib.get_resource_name(resource, name),
		"searchKey": sprintf("aws_dynamodb_table[%s].point_in_time_recovery", [name]),
		"issueType": "MissingAttribute",
		"keyExpectedValue": sprintf("aws_dynamodb_table[%s] used for Terraform state locking should have point_in_time_recovery enabled", [name]),
		"keyActualValue": sprintf("aws_dynamodb_table[%s] has no point-in-time recovery configured", [name]),
		"remediation": json.marshal({
			"before": "point_in_time_recovery undefined",
			"after": "point_in_time_recovery { enabled = true }",
		}),
		"remediationType": "addition",
	}
}
Policy migration dashboard showing Terraform governance rules and compliance status during migration

Phase 2: Policy Migration (Days 15-45)

Sentinel to OPA/Rego migration checklist:

  • Export all Sentinel policies and policy sets from TFC
  • Map each Sentinel rule to an equivalent OPA/Rego policy
  • Decide policy placement per rule: pre-plan, post-plan, approval gate, or periodic scan
  • Test each OPA policy against a known-good plan JSON: conftest test plan.json
  • Deploy policies to the new platform in advisory mode first (warn, don't block)
  • Run in parallel: keep Sentinel active on TFC while OPA runs on the new platform
  • After two weeks of clean parallel runs, switch OPA to enforcement mode
  • Deactivate Sentinel policies on TFC

For OPA/Rego implementation patterns in Terraform pipelines, modern cloud governance through policy-as-code covers the enforcement architecture.

The advisory-mode step exists for a specific reason: a Sentinel rule and its OPA/Rego translation are rarely byte-for-byte equivalent on the first attempt; edge cases in how each engine evaluates a plan JSON can differ in ways that only show up against real traffic, not a handful of test cases. Running the new policy in warn-only mode for two weeks surfaces those mismatches while Sentinel is still the actual enforcement layer.

Where Firefly fits in Phase 2 specifically: this checklist maps almost exactly onto Firefly's own policy authoring model, and onto a real enforcement mechanic worth naming directly rather than approximating. A Sentinel rule can be translated into Firefly through four paths depending on complexity and how much Rego expertise is available: a pre-built Policy Pack for common controls that don't need custom logic, the no-code rule builder for straightforward attribute or tag checks, hand-written Rego for anything genuinely custom, or AI-assisted generation from a plain-English description of what the Sentinel rule was doing, validated in a testing playground before it goes anywhere near production. A Sentinel rule blocking public S3 buckets, translated by hand into Firefly's policy schema, looks like this:

package Cx

import data.generic.terraform as tf_lib

CxPolicy[result] {
	resource := input.document[i].resource.aws_s3_bucket_public_access_block[name]
	resource.block_public_acls == false

	result := {
		"documentId": input.document[i].id,
		"resourceType": "aws_s3_bucket_public_access_block",
		"resourceName": tf_lib.get_resource_name(resource, name),
		"searchKey": sprintf("aws_s3_bucket_public_access_block[%s].block_public_acls", [name]),
		"issueType": "IncorrectValue",
		"keyExpectedValue": sprintf("aws_s3_bucket_public_access_block[%s].block_public_acls should be true", [name]),
		"keyActualValue": sprintf("aws_s3_bucket_public_access_block[%s].block_public_acls is set to false", [name]),
		"remediation": json.marshal({
			"before": "false",
			"after": "true",
		}),
		"remediationType": "replacement",
	}
}

The advisory-mode checklist step maps directly onto a real Guardrail setting rather than a workaround: every Firefly policy violation can be configured to block the deployment, alert an administrator without blocking, or allow an override for authorized users in specific circumstances. Setting a newly translated policy to alert-only during the two-week parallel run, then flipping it to block once it's proven clean, is the same mechanism the checklist describes, not an approximation. Firefly's five severity levels (Info, Low, Medium, High, Critical) give this a practical rollout order too: start Critical-severity translated rules in alert-only mode with the tightest review, and let Info/Low-severity rules move to enforcement faster, since the blast radius of an early mismatch is smaller.

Terraform Cloud migration cutover dashboard showing infrastructure changes and policy activity

Phase 3: Cutover (Days 45-90)

Cutover checklist:

  • Freeze TFC workspace configuration (no new variables, no new policies)
  • Run parallel deploys: push the same change through TFC and the new platform, and compare plan output.
  • Run a drift validation period: at least one full scan cycle on the new platform, confirming drift detection matches expectations.
  • Migrate CI/CD VCS integrations (GitHub/GitLab webhooks) to point at the new platform.
  • Update team documentation and runbooks
  • Define rollback criteria in advance: what specific conditions trigger reverting to TFC?
  • Decommission TFC workspaces after a 30-day post-migration clean period

The rollback criteria step is worth writing down explicitly rather than leaving it as a judgment call. "Revert if something breaks" isn't a criterion; it's a description of every incident. A usable version looks more like: revert if drift detection on the new platform flags more than a defined percentage of resources as unexpectedly changed within the first 72 hours, or if a policy enforcement gap lets through a change that Sentinel would have blocked.

Infrastructure event dashboard tracking resource changes during Terraform Cloud migration cutover

Where Firefly fits in Phase 3 specifically: the checklist's own rollback criteria example above, "more than a defined percentage of resources unexpectedly changed within 72 hours", is directly answerable from Firefly's Event Center rather than assembled by hand from scattered logs. Every mutation during the cutover window, whether it came through the console, CLI, the new platform's pipeline, or a stray script someone ran to unblock something quickly, gets logged with the identity responsible. Hence, the 72-hour rollback check is a query against a single source, not a manual cross-reference across TFC's logs, the new platform's logs, and CloudTrail separately.

For teams that want that rollback check answered directly rather than filtered manually, AI SRE handles it as a plain question: "Which resources changed in the last 72 hours and what changed?" It returns the same data Event Center holds, cross-referenced against Inventory and Governance in one response, which is the specific speed a cutover decision window actually needs.

Terraform Cloud migration rollback flowchart showing 72-hour checks and cutover rollback criteria

A Guardrail can also enforce the parallel-deploy comparison step directly, blocking a cutover-window plan that touches an unusually large blast radius without explicit sign-off, the infrastructure equivalent of a second pair of eyes on exactly the changes most likely to matter during the riskiest 45 days of the whole migration:

package Cx

import data.generic.terraform as tf_lib

CxPolicy[result] {
	count(input.document[i].resource_changes) > 15
	not input.document[i].metadata.cutover_approved

	result := {
		"documentId": input.document[i].id,
		"resourceType": "plan",
		"issueType": "IncorrectValue",
		"keyExpectedValue": "Plans touching more than 15 resources during the cutover window require explicit cutover_approved metadata",
		"keyActualValue": sprintf("Plan touches %v resources without cutover approval", [count(input.document[i].resource_changes)]),
		"remediationType": "manual_review",
	}
}

FAQs

How long does a Terraform Cloud migration actually take?

For most enterprise environments, budget the full 90-day window this playbook outlines. Smaller environments with fewer workspaces and simpler policy sets can compress this. Still, the parallel-operation windows (two weeks minimum for both state validation and policy advisory mode) are safety mechanisms worth keeping even on a faster timeline.

What's the biggest risk during cutover specifically?

State divergence and policy gaps are the two structural risks, but during cutover specifically, the most common practical failure is an undefined rollback trigger. Teams that haven't decided in advance what conditions justify reverting to TFC tend to either revert too late, after a real incident, or not at all, talking themselves out of a legitimate rollback because no clear criteria exist.

Can Terraform state be migrated without downtime?

Yes, if state locking is enabled on the new backend before any team member starts applying against it, and if the old backend is frozen (read-only) rather than left active in parallel with write access. The risk isn't downtime; it's two backends both accepting writes for the same workspace simultaneously.

Do all workspaces need to migrate at the same time?

No, and for larger environments, migrating in batches by team or environment is usually safer than a single cutover across every workspace at once. The four-phase structure in this playbook can run per batch, with earlier batches informing what to adjust before later ones start.

How does Firefly fit into a migration if it's not the execution platform?

Even when a different platform handles execution, Firefly's inventory and drift detection can run alongside the migration as an independent verification layer, catching drift that terraform plan alone can't see and providing a single, attributed mutation log across the entire cutover window rather than scattered logs across two platforms and CloudTrail.

Does Firefly replace the need for this migration playbook?

No, this playbook covers the mechanics of moving state and policy enforcement between platforms, which Firefly doesn't change. What Firefly adds at every phase is continuous, independently verified visibility; a Phase 0 baseline; a Phase 1 drift check beyond what Terraform plan can see; Phase 2's actual alert-vs-block mechanism; and Phase 3's single source of truth for the rollback decision.

Ready to see Firefly in action?

Discover how Firefly can help you recover your infrastructure from outages
and keep your cloud resilient