← Infra resources
Updated October 23, 2026 · By Kevra

Migrate From HCP Terraform to Terrakube

Moving from HCP Terraform to Terrakube is mostly a state move plus some bookkeeping. Terraform state is a standard file, Terrakube accepts the same cloud block and remote backend, and its docs describe two migration paths: a Workspaces Importer in the UI and the Terraform CLI (Terrakube migration guide). This guide walks through both, plus the parts neither path covers. Commands and API fields come from the Terrakube docs and source at release 2.33.3 and from HashiCorp's API docs, checked October 23, 2026.

Quick answer

StepWhat to do
1. InventoryList workspaces, execution mode, VCS repo, variables, variable sets and policies
2. Back up stateterraform state pull > backup.tfstate per workspace
3. Prepare TerrakubeOrganization, VCS connection, variable collections
4a. Import (many workspaces)Workspaces Importer with an HCP Terraform API token
4b. Or move one by oneChange the cloud block hostname, terraform login, terraform init -migrate-state
5. PoliciesRewrite Sentinel in Rego; adapt existing HCP OPA policies
6. Verifyterraform plan must report no changes
7. Cut overUpdate CI tokens, lock the old workspace

Sources: Terrakube migration guide, HCP Terraform workspaces API, checked October 23, 2026.

Step 1: Inventory your workspaces

Before touching anything, write down what each workspace has. The HCP Terraform API lists workspaces per organization at GET /organizations/:organization_name/workspaces, paginated, with attributes such as execution-mode, terraform-version, working-directory, vcs-repo-identifier and resource-count (Workspaces API). With a user or team token:

export TFC_TOKEN=...   # HCP Terraform user or team token
ORG=your-org
page=1
while [ -n "$page" ]; do
  resp=$(curl -s -H "Authorization: Bearer $TFC_TOKEN" \
    "https://app.terraform.io/api/v2/organizations/$ORG/workspaces?page%5Bsize%5D=50&page%5Bnumber%5D=$page")
  echo "$resp" | jq -r '.data[] | [.id, .attributes.name, .attributes["execution-mode"],
    .attributes["terraform-version"], (.attributes["vcs-repo-identifier"] // "cli"),
    .attributes["resource-count"]] | @tsv'
  page=$(echo "$resp" | jq -r '.meta.pagination["next-page"] // empty')
done > workspaces.tsv

For each workspace, also note:

Step 2: Back up every state file

Both migration paths copy state, but keep your own copy first. From an initialized working directory, terraform state pull prints the current state to stdout (terraform state pull):

terraform state pull > backup-$(date +%F).tfstate

Without a working directory, use the API. GET /workspaces/:workspace_id/current-state-version returns a hosted-state-download-url for the raw state (state versions API):

WS_ID=ws-XXXXXXXXXXXXXXXX
url=$(curl -s -H "Authorization: Bearer $TFC_TOKEN" \
  "https://app.terraform.io/api/v2/workspaces/$WS_ID/current-state-version" \
  | jq -r '.data.attributes["hosted-state-download-url"]')
curl -sL -H "Authorization: Bearer $TFC_TOKEN" "$url" -o "$WS_ID.tfstate"

Record the serial and lineage from each file. You will compare them after the move.

Step 3: Prepare Terrakube

Step 4a: Use the Workspaces Importer

For more than a handful of workspaces, start here. In the organization's workspace list, click Import Workspaces, choose Terraform Cloud or Terraform Enterprise, pick the workflow type, select the VCS connection for VCS workflows, and enter your API token (plus the host URL for Terraform Enterprise). Then select the workspaces to import. The docs say the importer copies "name, description, Terraform version, execution mode, variables, tags and the current state". If your workspaces use more than one workflow type, run the importer once per type (Terrakube migration guide).

Two details from the importer's source at 2.33.3 (WorkspaceService.java, Import.tsx) that the docs do not spell out:

The importer reads the state's JSON form as well. HCP Terraform only provides that for state written by Terraform 1.3 or later; without it the importer warns that plans and applies still work but the UI cannot show the JSON state.

Step 4b: Or move workspaces with the CLI

For a few workspaces, or when you want to control each one, change the configuration and let Terraform move the state. Before:

terraform {
  cloud {
    organization = "your-org"
    workspaces {
      name = "networking-prod"
    }
  }
}

After, with hostname set to your Terrakube API host. Terrakube's docs stress that hostname is required, since the default is app.terraform.io:

terraform {
  cloud {
    hostname     = "terrakube-api.example.com"
    organization = "your-org"
    workspaces {
      name = "networking-prod"
    }
  }
}

Terrakube's docs show name and list-style tags = ["networking", "prod"] in the workspaces block. If your HCP configuration uses project or map-style tags, switch to one of those forms. The backend "remote" block works too, with the same three settings.

Then log in to both hosts and migrate:

terraform login app.terraform.io            # if your session has expired
terraform login terrakube-api.example.com
terraform init -migrate-state

Terraform reads the state from HCP Terraform and writes it to the Terrakube workspace. Terrakube's docs also recommend a .terraformrc with plugin_cache_dir and disable_checkpoint = true for this path. If you start from a local state file instead, run terraform init and then terraform state push backup.tfstate.

This path moves state only. Recreate variables in the Terrakube UI, API or CLI, and reconnect the VCS repository if the workspace is VCS-driven.

Step 5: Policies

Terrakube runs OPA policies through templates, using a policy folder in your extensions repository (Terrakube OPA). It does not run Sentinel, so Sentinel policies have to be rewritten in Rego.

If you already use OPA policy sets in HCP Terraform, the Rego carries over with one change to check: HCP Terraform passes a combined document with plan data under input.plan and run data under input.run (HCP OPA policies), while Terrakube's example reads the plan JSON at the input root (input.resource_changes). Rules that use input.run need another source for that data. More in OPA policies in Terrakube.

Step 6: Verify with a plan

Run a plan against the Terrakube workspace before anything else:

terraform plan

You want "No changes. Your infrastructure matches the configuration." Then pull the state back and compare it with your backup:

terraform state pull | jq '{serial, lineage, n: (.resources | length)}'
jq '{serial, lineage, n: (.resources | length)}' backup-2026-10-23.tfstate

Same lineage and resource count means the right state arrived. If the plan shows changes, the usual cause is a missing or different variable, or a different Terraform version in the workspace settings. Do not apply until the plan is clean. Then do one full plan and apply cycle on a low-risk workspace before moving the rest.

Step 7: Cut over

Doing this on Kevra Infra

The steps are the same on Kevra Infra, which runs the open-source Terrakube as a managed service. Use your instance's hostname in the cloud block and in terraform login; there are no servers, database or storage to set up on your side. Your state stays standard Terraform state. Plans start at USD 39 per month with one organization. Kevra-specific guides are in the Kevra Infra docs.

Related: HCP Terraform's 500-resource free tier, Hosted Terrakube, HCP Terraform alternatives, connecting GitHub and GitLab to Terrakube, Terrakube with OpenTofu.

FAQ

Can I migrate from HCP Terraform to Terrakube without losing state?

Yes. Both the Workspaces Importer and terraform init -migrate-state copy the current state into Terrakube. Back up each state with terraform state pull first, and confirm with a terraform plan that shows no changes.

Does the Terrakube Workspaces Importer copy variables?

Yes. It copies workspace variables, tags, Terraform version, execution mode and current state. HCP Terraform does not return sensitive values, so the importer asks you to enter them; skipped ones are discarded and empty ones block runs until filled in.

Do I need to change my Terraform code?

Only the cloud block (or backend "remote"): add hostname with your Terrakube API host and keep organization and workspaces. Resources and modules stay the same.

What happens to my Sentinel policies?

Terrakube does not run Sentinel. Rewrite them in Rego for OPA. Existing HCP Terraform OPA policies mostly carry over, but they read plan data from input.plan, while Terrakube's example reads it from the input root.

What about HCP Terraform variable sets?

Terrakube's equivalent is a variable collection. Create the collections first; the importer can then map each variable set attached to a workspace to a collection.

Can I migrate to OpenTofu at the same time?

You can, since Terrakube runs Terraform or OpenTofu, but change one thing at a time. Move the platform first, get a clean plan, then switch the tool.

Migrate to hosted Terrakube

Kevra Infra runs the open-source Terrakube platform for Terraform and OpenTofu, so you move your workspaces, not your servers. Plans start at USD 39 per month. Want to try it first? Ask us for a trial.

Terrakube is a trademark of its owners. Kevra is not affiliated with, endorsed by or sponsored by the Terrakube project. Kevra Infra runs the open-source Terrakube project (Apache-2.0) as a managed service.