> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ubiquex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Terraform

> Convert existing Terraform configurations to .iac with ubx convert, then import live state.

Moving from Terraform to ubx doesn't require a big-bang rewrite or a maintenance window. The migration path is incremental: convert one module at a time, import the existing resources into Pulumi state so nothing gets recreated, and keep the rest of Terraform running until you're ready to cut over entirely. `ubx convert --from terraform` handles the mechanical conversion — it reads your `.tf` files and generates equivalent `.iac` source. The converter handles the obvious cases automatically: `variable` → `input`, `output` → `output`, `resource` → `unit`. The cases that require manual attention — Terraform resource type names that differ from Pulumi's, versioning sub-resources that become sub-blocks, multi-resource patterns that collapse to a single block — are flagged in the MIGRATION.md the converter produces alongside the converted files.

## What you'll learn

* How `ubx convert --from terraform` converts `.tf` files to `.iac`
* The common manual fixups required after conversion
* How to import existing Terraform-managed resources into Pulumi state

***

## Why this matters

<Info>
  You don't need to migrate everything at once. Convert one module, import its resources, verify it validates and plans correctly, then move on to the next. The rest of your Terraform configuration keeps running unchanged during the migration — ubx and Terraform can coexist in the same account, managing separate resources.
</Info>

***

## The source code

<CodeGroup>
  ```hcl main.iac theme={"theme":"css-variables"}
  // Post-migration .iac — result of ubx convert + manual fixups.
  // See terraform-before/main.tf for the original Terraform source.

  unit "aws_s3_bucket_v2" "assets" {
    bucket     = input.bucket_name
    tags       = { Environment = input.env, ManagedBy = "ubx" }
    versioning = { enabled = true }   // collapsed from separate aws_s3_bucket_versioning resource
  }

  unit "aws_rds_instance" "db" {
    engine                  = "postgres"
    instance_class          = "db.t3.micro"
    identifier              = "${input.env}-db"
    username                = "admin"
    password                = "changeme"
    storage_encrypted       = true
    backup_retention_period = 7
  }
  ```

  ```hcl terraform-before/main.tf theme={"theme":"css-variables"}
  terraform {
    required_providers {
      aws = {
        source  = "hashicorp/aws"
        version = "~> 5.0"
      }
    }
  }

  variable "env" {
    type    = string
    default = "prod"
  }

  variable "bucket_name" {
    type = string
  }

  resource "aws_s3_bucket" "assets" {
    bucket = var.bucket_name
    tags = {
      Environment = var.env
      ManagedBy   = "terraform"
    }
  }

  # In ubx this collapses into the versioning sub-block on the bucket
  resource "aws_s3_bucket_versioning" "assets" {
    bucket = aws_s3_bucket.assets.id
    versioning_configuration {
      status = "Enabled"
    }
  }

  resource "aws_db_instance" "db" {
    engine            = "postgres"
    instance_class    = "db.t3.micro"
    identifier        = "${var.env}-db"
    username          = "admin"
    password          = "changeme"
    storage_encrypted = true
    skip_final_snapshot = true
  }

  output "bucket_name" { value = aws_s3_bucket.assets.bucket }
  output "db_endpoint" { value = aws_db_instance.db.endpoint }
  ```

  ```hcl inputs.iac theme={"theme":"css-variables"}
  input "env" {
    type    = "string"
    default = "prod"
  }

  input "bucket_name" {
    type    = "string"
    default = "myapp-assets"
  }
  ```

  ```hcl outputs.iac theme={"theme":"css-variables"}
  output "bucket_name" { value = unit.aws_s3_bucket_v2.assets.bucket }
  output "db_endpoint"  { value = unit.aws_rds_instance.db.endpoint }
  ```

  ```hcl ubx.iac theme={"theme":"css-variables"}
  ubx {
    name    = "migration-from-terraform"
    runtime = "typescript"
    stacks  = ["dev", "staging", "prod"]
  }

  backend "s3" {
    bucket = "my-ubx-state"
    region = "us-east-1"
    key    = "${stack}/migration-from-terraform.tfstate"
  }
  ```
</CodeGroup>

***

## How it works

<Steps>
  <Step title="Run ubx convert to generate .iac files">
    `ubx convert --from terraform ./terraform-before/ --out ./` reads all `.tf` files in the source directory and generates `.iac` equivalents. The converter handles `variable` → `input`, `output` → `output`, `resource` → `unit`, and basic expression translation (`var.x` → `input.x`, `resource.type.name.attr` → `unit.type.name.attr`).
  </Step>

  <Step title="Apply manual fixups from MIGRATION.md">
    The converter produces a `MIGRATION.md` alongside the `.iac` files listing cases it couldn't handle automatically. Common fixups: `aws_s3_bucket` → `aws_s3_bucket_v2` (Pulumi naming differs from Terraform), separate `aws_s3_bucket_versioning` resource → `versioning` sub-block inside the bucket, `aws_db_instance` → `aws_rds_instance`.
  </Step>

  <Step title="Import existing resources into Pulumi state">
    Add `import "aws_s3_bucket_v2" "assets" { id = "myapp-assets" }` blocks for each resource that already exists in AWS. The first `ubx apply` adopts them into Pulumi state without recreating them. Remove the import blocks after the first successful apply.
  </Step>
</Steps>

***

## Common conversion patterns

| Terraform                           | ubx .iac                         | Notes                      |
| ----------------------------------- | -------------------------------- | -------------------------- |
| `variable "x" {}`                   | `input "x" {}`                   | Direct mapping             |
| `output "x" {}`                     | `output "x" {}`                  | Direct mapping             |
| `resource "aws_s3_bucket" "x" {}`   | `unit "aws_s3_bucket_v2" "x" {}` | Provider naming differs    |
| `var.x`                             | `input.x`                        | Reference syntax           |
| `resource.type.name.attr`           | `unit.type.name.attr`            | Pending ref syntax         |
| `aws_s3_bucket_versioning` resource | `versioning {}` sub-block        | Sub-resource → sub-block   |
| `aws_db_instance`                   | `aws_rds_instance`               | Pulumi vs Terraform naming |

***

## Common mistakes

<Warning>
  Terraform resource type names often differ from Pulumi's. `aws_s3_bucket` in Terraform is `aws_s3_bucket_v2` in Pulumi. `aws_db_instance` is `aws_rds_instance`. Always check `ubx docs <type>` after conversion to verify the correct Pulumi resource type name before importing.
</Warning>

<Tip>
  Keep your Terraform state file accessible during migration. Use `from = "terraform://s3/..."` on `input` blocks (tutorial 17) to consume Terraform outputs in your new ubx stacks while the rest of the infrastructure is still Terraform-managed. This allows gradual migration without a forced cutover.
</Tip>

***

## Run it

```bash theme={"theme":"css-variables"}
# Convert
ubx convert --from terraform ./terraform-before/ --out ./

# Review MIGRATION.md and apply manual fixups

# Validate
ubx validate

# Add import blocks for existing resources, then apply
ubx apply    # requires AWS credentials; imports existing resources
# Remove import blocks after successful apply
```

***

## What you learned

<Check>`ubx convert --from terraform` converts `.tf` files to `.iac` automatically</Check>
<Check>`MIGRATION.md` lists fixups that require manual attention after conversion</Check>
<Check>`import` blocks adopt existing resources into Pulumi state without recreating them</Check>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Migrate from Pulumi" href="/v1/tutorials/55-migration-from-pulumi">
    Convert existing Pulumi TypeScript programs to .iac
  </Card>

  <Card title="Input from Terraform state" href="/v1/tutorials/17-input-from-terraform-state">
    Consume Terraform outputs during incremental migration
  </Card>
</CardGroup>

***

<Info>
  Full runnable example: [github.com/ubiquex/ubx-examples/54-migration-from-terraform](https://github.com/ubiquex/ubx-examples/tree/main/54-migration-from-terraform)
</Info>
