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 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:
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: trueproperties becomeComputed— server-assigned, never written from config.requiredproperties becomeRequired; everything else isOptional.uniqueItems: truearrays 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.
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 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.