Best Practices
Terraform Best Practices
These practices keep a Terraform-managed Monad organization predictable. New to the provider? Start with the Terraform overview.
Pin the Provider's Minor Version
The provider is pre-1.0, so a breaking change ships as a minor version bump (for example 0.4 → 0.5), not a major one. Pin to a minor series and move to the next one deliberately:
Code
A looser constraint such as ~> 0.5 accepts every later 0.x release, including breaking ones.
Commit .terraform.lock.hcl so every run uses the same build.
Before raising the pin, read the changelog, which gives the migration path for each breaking change, and review the resulting terraform plan before applying it.
Keep Credentials Out of Your Files
- Supply the API key through
MONAD_API_TOKENor asensitivevariable, never a literal in the provider block. - Supply secret values through
sensitivevariables (TF_VAR_*, a CI secret, or a secrets-manager data source), never a literal in a.tffile. - Reference secrets from components as
{ id = monad_secret.<name>.id }.
Secret values are write-only: Terraform sends them to Monad but never writes them to state or plan output. To rotate a secret, change the value you supply and apply; the provider notices the change and updates the secret in place.
Use One Configuration per Organization
API keys are scoped to a single organization, and every resource a provider block creates lands in that provider's organization_id.
Keep each organization in its own Terraform configuration and state.
When one configuration must manage several organizations (a root organization and its teams, for example), declare one provider block per organization with an alias, each with that organization's own API key.
Let Terraform Own What It Manages
Terraform compares your configuration with what is in Monad on every plan. A change made in the Monad UI to a Terraform-managed resource shows up in the next plan as drift, and the next apply reverts it. Make changes to managed resources in code; if you change something in the UI to test it, copy the change back into the configuration before the next apply.
Two settings behave differently on purpose:
enabledon a pipeline is adopted from Monad when you leave it out of the configuration, so enabling or disabling a pipeline in the UI is not reverted. Set it explicitly when you want Terraform to enforce it.- Schema drift detection is off on any edge whose configuration has no
schema_detection_specblock. Declare the block on every edge where detection should stay on; see Schema Drift Detection.
Create Pipelines Disabled, Then Enable
Create a new pipeline with enabled = false.
Once secret values are set and the pipeline looks right in the Monad UI, change it to enabled = true and apply again.
This keeps a half-configured pipeline from pulling data or delivering it to a destination.
Rehearse in a Sandbox Organization
Try a new configuration, a provider upgrade, or a large refactor against a test organization before applying it to production.
A clean terraform plan shows what will change, not the order the API will accept the changes in; the next section is the most common example.
Replace a Pipeline's Component in Two Steps
Monad refuses to delete a component that is still part of a pipeline.
If one change both removes a component and points the pipeline at its replacement, Terraform may try the delete before the pipeline update, and the apply stops partway with an error such as cannot delete an input that is a part of one or more pipelines.
Split the swap into two applies:
- Add the new component and point the pipeline at it, keeping the old component's resource block in place. Apply.
- Remove the old component's resource block. Apply.
If a combined change has already failed partway, update the pipeline on its own, then apply everything:
Code
The same applies to transforms, enrichments and outputs.
Give Large Applies Time
Monad processes pipeline creation one request at a time, so a configuration that creates many pipelines at once can take a few minutes.
Each API call has a five-minute budget by default.
Raise it for one resource with a timeouts block, or for every call with request_timeout:
Code
If a pipeline create still runs out of time, the provider looks for the pipeline the API finished creating and adopts it into state rather than leaving a duplicate for the next apply to create.
Running the first apply of a large configuration with terraform apply -parallelism=1 avoids the contention altogether.
Run Terraform from CI
Treat the configuration like any other infrastructure code:
- Keep state in a remote backend with locking, so two runs cannot apply at once. State holds no secret values, but it does hold your full pipeline configuration, so restrict access to it.
- Post
terraform planoutput on each pull request for review. - Apply only from the main branch, using a dedicated API key for CI so it can be rotated or revoked on its own.