Skip to content

How to migrate from Terraform Cloud to OpenTofu, one workspace at a time

You can leave Terraform Cloud with ordinary tofu commands and no special import tool. This guide moves one workspace at a time, so every step is small and reversible.

Plan the move

Migrate one workspace at a time, starting with something low-risk such as a development environment. For each workspace, write down:

  • its Terraform version, so you can pick a compatible OpenTofu version;
  • its variables, and where the sensitive values come from;
  • how it authenticates to your cloud;
  • its outputs and resource addresses, to compare after the move; and
  • any Sentinel or OPA policies attached to it.

If you haven't switched from Terraform to OpenTofu yet, do that first while still on Terraform Cloud. Our OpenTofu vs Terraform post covers what to check.

Prepare the destination

  1. Create a StackShip organization, then a project and a workspace. Pick the same OpenTofu version you tested with.
  2. Recreate the workspace variables. Copy sensitive values from your secret manager: Terraform Cloud won't show them again.
  3. Set up a credential profile for AWS, Google Cloud, or Azure. It uses short-lived federation, so there are no access keys to copy across. See short-lived cloud credentials.
  4. Connect the GitHub repository if you want pull request plans.

Export state from Terraform Cloud

Lock the source workspace in Terraform Cloud so nothing else can write to it. Then, from a directory still configured for Terraform Cloud, pull the current state:

tofu state pull > source-state.json

Keep this file somewhere safe until the migration is finished.

Push state into StackShip

In a fresh checkout of your configuration, change the cloud block to point at StackShip. Don't copy the old .terraform directory.

terraform {
  cloud {
    hostname     = "stackship.run"
    organization = "your-org-slug"

    workspaces {
      name = "network-production"
    }
  }
}

Sign in, initialize, and push the exported state:

tofu login stackship.run
tofu init -input=false
tofu state push source-state.json

For a scripted migration, create a workspace token with the State migration purpose instead of using tofu login, and export it as TF_TOKEN_stackship_run.

Verify

tofu state pull > stackship-state.json
tofu plan -refresh=false

Compare outputs and resource addresses with what you recorded. A clean plan should show no unexpected changes. State moved into an empty workspace starts a new lineage with serial 1; your resources and outputs are unchanged.

What state migration doesn't copy

ItemWhat to do
VariablesRecreate them; copy secrets from your secret manager.
Cloud credentialsCreate a credential profile and apply its trust template.
VCS settingsConnect the repository through the StackShip GitHub App.
Sentinel policiesRewrite them in Rego. See OPA policy for OpenTofu plans.
Members and teamsInvite people, or connect SSO and SCIM.
Run and audit historyExport what you need to keep before closing the old workspace.

Cut over

  1. Make sure only StackShip can write to this state. Remove the VCS connection or disable runs on the old workspace.
  2. Start a run: push to the tracked branch, or run tofu apply.
  3. Check the policy result, approve the plan, and apply.

Never let two systems apply to the same infrastructure. Keep the exported state file until you have completed a clean plan and apply in StackShip.

Next steps

The migration reference in the docs covers moving local state and other backends too. To compare features before you start, read StackShip vs Terraform Cloud.

Get started

Run your first OpenTofu plan today.

Free for every organization. Sign up with email or Google.