> For the complete documentation index, see [llms.txt](/llms.txt)

# The generated Terraform provider

If your API creates things customers want to manage as infrastructure — projects, webhooks, API
keys, environments — they will eventually want to declare them in Terraform rather than script them
by hand. From the same [Glotto IR](/docs/glotto-ir) as your SDKs, docs site and MCP server, Glotto
generates a **complete, publishable Terraform provider**: a Go module built on
`terraform-plugin-framework`, with a resource per resource in your API, data sources, Registry
documentation, and an acceptance-test scaffold.

Enable it in `glotto.yml`:

```yaml
targets:
  terraform: {}
```

`glotto generate` then writes the provider module under `<out>/terraform/`.

## What gets emitted

A module you can `go build`, tag, and publish — not a scaffold to fill in:

| Path | What it is |
|---|---|
| `go.mod` | the provider module, pinning `terraform-plugin-framework` |
| `main.go` | the `providerserver` entrypoint |
| `internal/provider/provider.go` | the provider wiring, an embedded HTTP client configured from provider config, and every resource, data source and ephemeral resource |
| `internal/provider/*_test.go` | a `TF_ACC`-gated acceptance-test scaffold, one per managed resource, plus the shared harness |
| `docs/` | the Terraform Registry docs tree — `index.md`, `resources/*.md`, `data-sources/*.md` |
| `terraform-registry-manifest.json`, `.goreleaser.yml` | what the Registry's publishing flow expects |

The Registry docs are emitted natively from the same schema derivation as the provider code, so
they cannot drift from the schema they document — and no `tfplugindocs` or `terraform` binary is
needed to produce them.

## Resources and data sources

Each resource in your API becomes a managed resource type, named from the provider's type prefix and
the resource's path — `glotto_webhook`, and `glotto_project_environment` for a subresource. Its CRUD
operations map to Terraform's lifecycle from the operations your spec declares — create, read,
update, delete — and resources are importable by id.

The provider's own publishing identity is not yet configurable from `glotto.yml`: the type prefix is
`glotto` and the Registry namespace defaults to `glotto-dev`. Surfacing those as per-target config is
not supported yet.

Where a resource has a read operation, it also becomes a **data source**, so a practitioner can
reference something they did not create. Collection endpoints emit a list data source alongside the
single-item one.

An operation whose result is a short-lived credential — marked `x-glotto-terraform-ephemeral` in
your spec — registers as an **ephemeral resource** instead, so its value never lands in Terraform
state. Renewal and session-close hints (`x-glotto-terraform-renew-at`, `-ttl-seconds`,
`-close-operation`) drive the corresponding framework callbacks.

## Attribute shaping

Attributes are derived from your models, and the shaping follows standard OpenAPI where it can:

- `readOnly: true` properties become `Computed` — server-assigned, never written from config.
- `required` properties become `Required`; everything else is `Optional`.
- `uniqueItems: true` arrays become sets rather than lists, so ordering is not spurious diff noise.

Where the spec's own vocabulary isn't enough, the `x-glotto-terraform-*` extensions override the
inference per property — and those overrides win, so you can correct a schema you don't control
without editing it. Migrating from Stainless? Glotto translates
the equivalent `x-stainless-*` extensions into these automatically — see
[Bring your Terraform attribute shaping across](/docs/migrate-from-stainless#bring-your-terraform-attribute-shaping-across).

## Publishing

The emitted module is the unit you publish: tag it and let the included `.goreleaser.yml` build the
release artifacts the Terraform Registry expects, with `terraform-registry-manifest.json` declaring
the protocol version. The provider carries a `LICENSE` file; Glotto stamps no licence terms into
your provider's source.

## Kept true, not just generated

Like every Glotto artifact, the provider is a deterministic projection of your spec: byte-stable
output, locked by golden tests, and **compile-verified** — the generated Go module is built in CI
on every change to the engine, so a provider that would not compile never ships. It is regenerated
in lockstep with your SDKs and docs from the same IR, and the [drift gate](/docs/drift-detection)
proves the committed provider never lags your spec.

Add a resource, mark a field read-only, deprecate an endpoint — your provider is provably current
on the next regeneration, and your practitioners' configurations keep describing a real API.
