Migrating Terraform state from one backend to another

Terraform state management accept an easy migration from one backend to another, either this backend is remote or local. It detects the actual change on the object backend within the context terraform and apply the proper changes to execute the migration.

Within a repository with an already initialized state, run the following:

terraform init -migrate-state

Example migration to Gitlab

When not defining a backend, Terraform use a local backend by default, to migrate to Gitlab just create a backend.tf file with the following:

terraform {
  backend "http" {
  }
}

Below a more complex example migrating a state file from a local machine to Gitlab using glab. Before running it configure glab to properly point to your Gitlab instance, it assumes that the username of the user in the current machine is the same on the Gitlab (result of whoami), and that the variable GITLAB_ACCESS_TOKEN has a valid token.

export TF_STATE_NAME=default
export GITLAB_HOST="$(glab config get host)"
export PROJECT_ID="$(glab api projects/:fullpath/ | jq '.id')"
export PROJECT_URL="https://${GITLAB_HOST}/api/v4/projects/${PROJECT_ID}"
export BASE_URL="${PROJECT_URL}/terraform/state/${TF_STATE_NAME}"
terraform init -migrate-state\
    -backend-config="address=${BASE_URL}" \
    -backend-config="lock_address=${BASE_URL}/lock" \
    -backend-config="unlock_address=${BASE_URL}/lock" \
    -backend-config="username=$(whoami)" \
    -backend-config="password=$GITLAB_ACCESS_TOKEN" \
    -backend-config="lock_method=POST" \
    -backend-config="unlock_method=DELETE" \
    -backend-config="retry_wait_min=5"

The following is the output of the command above if is successful:

Initializing the backend...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "http" backend. No existing state was found in the newly
  configured "http" backend. Do you want to copy this state to the new "http"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes


Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Reusing previous version of telmate/proxmox from the dependency lock file
- Using previously-installed telmate/proxmox v3.0.1-rc4

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Appendix

The script for migrating to Gitlab above wrapped in a nice function:

function terraform-state-migrate-to-gitlab() {
    local TF_STATE_NAME=default
    local GITLAB_HOST="$(glab config get host)"
    local PROJECT_ID="$(glab api projects/:fullpath/ | jq '.id')"
    local PROJECT_URL="https://${GITLAB_HOST}/api/v4/projects/${PROJECT_ID}"
    local BASE_URL="${PROJECT_URL}/terraform/state/${TF_STATE_NAME}"
    terraform init -migrate-state\
        -backend-config="address=${BASE_URL}" \
        -backend-config="lock_address=${BASE_URL}/lock" \
        -backend-config="unlock_address=${BASE_URL}/lock" \
        -backend-config="username=$(whoami)" \
        -backend-config="password=$GITLAB_ACCESS_TOKEN" \
        -backend-config="lock_method=POST" \
        -backend-config="unlock_method=DELETE" \
        -backend-config="retry_wait_min=5"
}