# API has separate project_id, region, and name fields
Source: https://speakeasy.com/blog/release-terraform-jq-transformations

import { CalloutCta } from "@/components/callout-cta";

<CalloutCta
  title="Migrate your Terraform provider"
  description="We're on a mission to automate even the messiest Terraform providers. If you want to talk about how we could support your team, grab time!"
  buttonText="Book a session"
  buttonHref="/book-demo"
/>

Moving an existing Terraform provider to code generation isn't always straightforward. The provider you built by hand likely evolved over time with naming conventions, structural decisions, and interface choices that made sense for your users—but don't exactly match your API.

Maybe you simplified tag management by using a map instead of the array-of-objects structure your API returns. Perhaps you concatenated multiple API fields into a single identifier. These thoughtful design decisions improve the user experience, but they create a challenge when migrating to a provider generated from an OpenAPI spec.

We've added support for data transformations in Speakeasy's Terraform provider generator. Using JQ expressions, you can transform data between your provider's interface and your API's structure, maintaining your existing interface while moving to generated code.

## The migration challenge

Existing Terraform providers often diverge from their underlying APIs in useful ways. These differences accumulate as you refine the provider based on user feedback, add convenience features, or work around API quirks.

Here are common patterns that create migration challenges:

### Structural simplification

Many APIs represent tags or labels as arrays of objects:

```json
{
  "tags": [
    { "key": "environment", "value": "production" },
    { "key": "team", "value": "platform" },
    { "key": "cost-center", "value": "engineering" }
  ]
}
```

But from a Terraform user's perspective, this structure is unnecessarily complex. A simple map is more ergonomic:

```hcl
resource "platform_instance" "main" {
  name = "api-server"

  tags = {
    environment  = "production"
    team         = "platform"
    cost-center  = "engineering"
  }
}
```

Your hand-coded provider handles this transformation internally. Moving to generation means either accepting the more complex API structure or finding a way to maintain the simplified interface.

### Composite identifiers

Some APIs split related identifiers across multiple fields, but Terraform providers often combine them for convenience:

```hcl