info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# GitLab managed Terraform State **(FREE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 13.0.
Neither Terraform nor GitLab encrypts the plan file by default. If your Terraform plan
includes sensitive data such as passwords, access tokens, or certificates, GitLab strongly
recommends encrypting plan output or modifying the project visibility settings.
### Example project
See [this reference project](https://gitlab.com/gitlab-org/configure/examples/gitlab-terraform-aws) using GitLab and Terraform to deploy a basic AWS EC2 in a custom VPC.
## Using a GitLab managed Terraform state backend as a remote data source
You can use a GitLab-managed Terraform state as a
[Terraform data source](https://www.terraform.io/docs/language/state/remote-state-data.html).
To use your existing Terraform state backend as a data source, provide the following details
as [Terraform input variables](https://www.terraform.io/docs/language/values/variables.html):
- **address**: The URL of the remote state backend you want to use as a data source.
For example, `https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>`.
- **username**: The username to authenticate with the data source. If you are using a [Personal Access Token](../../profile/personal_access_tokens.md) for
authentication, this is your GitLab username. If you are using GitLab CI, this is `'gitlab-ci-token'`.
- **password**: The password to authenticate with the data source. If you are using a Personal Access Token for
authentication, this is the token value. If you are using GitLab CI, it is the contents of the `${CI_JOB_TOKEN}` CI/CD variable.
An example setup is shown below:
1. Create a file named `example.auto.tfvars` with the following contents:
1. Define the data source by adding the following code block in a `.tf` file (such as `data.tf`):
```hcl
data "terraform_remote_state" "example" {
backend = "http"
config = {
address = var.example_remote_state_address
username = var.example_username
password = var.example_access_token
}
}
```
Outputs from the data source can now be referenced in your Terraform resources
using `data.terraform_remote_state.example.outputs.<OUTPUT-NAME>`.
You need at least the [Developer role](../../permissions.md) in the target project
to read the Terraform state.
## Migrating to GitLab Managed Terraform state
Terraform supports copying the state when the backend is changed or
reconfigured. This can be useful if you need to migrate from another backend to
GitLab managed Terraform state. Using a local terminal is recommended to run the commands needed for migrating to GitLab Managed Terraform state.
The following example demonstrates how to change the state name, the same workflow is needed to migrate to GitLab Managed Terraform state from a different state storage backend.
You can obtain the `<global_id_for_the_state>` by querying the list of states:
```shell
query ProjectTerraformStates {
project(fullPath: "<your_project_path>") {
terraformStates {
nodes {
id
name
}
}
}
}
```
For those new to the GitLab GraphQL API, read
[Getting started with GitLab GraphQL API](../../../api/graphql/getting_started.md).
## Troubleshooting
### Unable to lock Terraform state files in CI jobs for `terraform apply` using a plan created in a previous job
When passing `-backend-config=` to `terraform init`, Terraform persists these values inside the plan
cache file. This includes the `password` value.
As a result, to create a plan and later use the same plan in another CI job, you might get the error
`Error: Error acquiring the state lock` errors when using `-backend-config=password=$CI_JOB_TOKEN`.
This happens because the value of `$CI_JOB_TOKEN` is only valid for the duration of the current job.
As a workaround, use [http backend configuration variables](https://www.terraform.io/docs/language/settings/backends/http.html#configuration-variables) in your CI job,
which is what happens behind the scenes when following the
[Get started using GitLab CI](#get-started-using-gitlab-ci) instructions.