Infrastructure-as-Code Fixes
How CostLens applies cost fixes to Terraform-managed resources by opening a pull request in your own repository, instead of changing your cloud account directly.
Most CostLens fixes apply directly to your cloud account. For resources you manage as Terraform code, that creates a problem: the change happens in AWS, but your Terraform state and .tf files no longer describe reality — the next terraform apply could silently undo the fix, or produce unexpected drift somewhere else.
Infrastructure-as-Code (IaC) Remediation takes a different approach for those resources: instead of changing your cloud account, CostLens edits your Terraform code, commits it to a new branch, and opens a pull request (or merge request, on GitLab) in your own repository. Your team reviews, approves, and merges it like any other code change, and your existing CI pipeline runs terraform apply. CostLens never touches the cloud resource directly for a fix delivered this way, and it never merges anything on its own.
Where to find it
On any recommendation whose resource CostLens has mapped to Terraform, the usual Apply Fix button is replaced with Fix via pull request — right on the recommendation's detail page. There's no separate page to visit first.
Why it matters
- Your Terraform stays the source of truth. The fix lives in your code and state, not as an out-of-band change nobody remembers making.
- Your existing review process still applies. The pull request is a normal PR/MR — branch protections, required reviewers, and CI checks all apply exactly as they do to any other change.
- Nothing merges without a human. CostLens opens the PR and stops there. You decide when, or whether, it merges. It never writes to your repository's default branch and never runs
terraform applyitself. - Savings are still tracked. Once the PR merges and CostLens confirms the change actually took effect, the recommendation is marked implemented and its savings are credited to your realized-savings totals — the same tracking used for a fix CostLens applies directly.
Worked example: resizing an over-provisioned EC2 instance
This is the flow end to end, using the most common case — CostLens recommends resizing an over-provisioned EC2 instance, and that instance is defined in your Terraform.
CostLens flags the resource
A regular analysis run finds an EC2 instance running well under its provisioned capacity and creates an EC2 Right-sizing recommendation, exactly as it would for any AWS account — the detection doesn't change because the resource happens to be IaC-managed.
CostLens recognizes the resource is Terraform-managed
Opening the recommendation shows a banner: "This resource is Terraform-managed — CostLens opens a pull request instead of applying live." The regular Apply Fix button is not offered for this resource; Fix via pull request is, instead. CostLens recognizes a resource is Terraform-managed from your connected state or repository first, and — when neither has a match — from a tag on the resource itself (see below).
Click 'Fix via pull request'
A dialog opens and looks up which repository, file, and Terraform resource address this EC2 instance maps to — checking your connected Terraform state first (if you've pointed CostLens at one), then falling back to scanning your repository's .tf files for a resource tagged or labelled as this instance.
Confirm the mapping (first time only)
The very first time CostLens maps a recommendation to a specific repository, file, and resource address, an organization admin confirms it's correct before anything is generated. CostLens remembers that mapping, so the next recommendation on the same instance skips straight to the diff.
Review the generated diff
CostLens shows the exact HCL change it proposes — in this example, just the instance_type attribute, changed from (say) m5.2xlarge to m5.xlarge. Nothing else in the file is touched. If that value is actually set through a variable or a module input rather than hardcoded in place, CostLens edits it there instead of rewriting the module call. Alongside the diff you'll see a terraform plan summary (run by CostLens's own sandboxed plan, or your connected CI pipeline if you use one) confirming the change is what it claims to be, and — because this is a modify, not a delete — a note that it's reversible in git: closing or reverting the PR is enough, CostLens never applies anything from here.
Acknowledge drift, if flagged
If your live cloud resource no longer matches what your Terraform state says it should be, CostLens flags the mismatch here and requires an explicit checkbox before it will open a PR against out-of-date state — patching against stale state could make things worse, not better.
Click 'Create pull request'
CostLens creates a feature branch, commits the one-line change, and opens the PR/MR. The description includes the recommendation, the estimated monthly and annual savings, the risk/rollback note, and a link back to the recommendation in CostLens. You'll see a link to open it directly in GitHub or GitLab.
Your team reviews and merges — or doesn't
This is a normal pull request in your own repository. Branch protections, required reviewers, and CI checks all apply exactly as they do to any other change. CostLens never merges it and never pushes directly to your default branch.
Your CI applies it, CostLens verifies and credits the savings
After the PR merges and your pipeline runs terraform apply, CostLens checks (on its next sync) that the live instance actually changed to m5.xlarge, marks the recommendation implemented, and credits the realized savings — the same realized-savings tracking used for a fix CostLens applies directly.
Deletes work the same way, with an extra checkpoint
For a recommendation that removes a resource — an unused EBS volume or an unattached Elastic IP, for example — the diff is a resource-block deletion instead of an attribute edit. CostLens marks these high risk and requires two separate confirmations before it will open the PR ("I understand this removes the Terraform resource block" and "A human must review and merge this PR — CostLens will not auto-merge") on top of the usual review. Everything else in the flow is identical.
Rolling back a merged IaC fix
Because CostLens never touches your cloud account for these fixes, rollback isn't a live undo — it's a second pull request that reverts the first. From Fix History, rolling back a merged IaC fix opens a revert PR on a new feature branch; once your team merges that and your pipeline applies it, the resource is back to its previous state. CostLens never makes the change directly, before or after the fact.
How CostLens recognizes a Terraform-managed resource
Detection checks three signals, in order, and stops at the first match:
- Your connected Terraform state — the most reliable signal, since state records the exact cloud id CostLens is looking for.
- A scan of your connected repository's
.tffiles — used when state doesn't have a match (or isn't connected), looking for a resource block of the right type. - A tag on the resource itself — used only when neither of the above found anything. CostLens recognizes a broad set of common conventions out of the box: a
managed-by,provisioner, orcreated-bytag whose value names Terraform or OpenTofu; a bareterraform: true-style tag; or a Terraform Cloud/Enterpriseterraform-workspacetag (any value). A tag match alone tells CostLens the resource is Terraform-managed, but not where — you'll still confirm the repository, file, and address the first time, exactly as with a state or HCL match.
Using a different tagging convention?
If your organization tags Terraform-managed resources differently from the built-in patterns above, an admin can add your own key/value convention under Settings → Integrations → Custom Terraform tags. Custom rules are checked in addition to the built-in defaults, never instead of them, and a blank value means "any value under this key counts."
What's supported today
| IaC tool | Terraform only |
| Source control | GitHub and GitLab (Bitbucket isn't supported yet) |
| Cloud provider | AWS only |
| Fix types | EC2 and RDS right-sizing (resize) · EBS gp2 → gp3 migration · deleting unused/unattached EBS volumes, orphaned snapshots, and unattached Elastic IPs · CloudWatch Log Group retention policy · off-hours start/stop scheduling for EC2 and RDS |
Reservation and Savings Plan purchases are never handled this way — those stay a manual decision in CostLens, as they are today. A resource CostLens can't map to Terraform (or a check type not in the list above) keeps using the regular, direct Apply Fix flow instead.
Setting it up
Connect your Git provider
Go to Settings → Integrations, find the GitHub or GitLab card, and connect it (admin only). For IaC Remediation specifically, the access token needs Contents and Pull requests write on GitHub, or the api scope on GitLab — the same connection used for cost-alert issues also carries the PR/MR permission this feature needs. See Git Integration for the full walkthrough.
Point CostLens at your Terraform state (optional, recommended)
Connecting a read-only pointer to your Terraform state backend (S3, GCS, Azure Storage, or Terraform Cloud) makes resource matching start from state — the most reliable source — instead of scanning .tf files. This step doesn't have a self-service page yet; open a support case or reach out to your CostLens contact and they'll set it up with you. Skipping this step doesn't block the feature — CostLens falls back to matching resources tagged or labelled managed-by: terraform in your repository.
Open a recommendation for an IaC-managed resource
Nothing else to configure — the next time a recommendation's resource resolves to a Terraform address, its detail page shows Fix via pull request instead of Apply Fix, and you're in the flow described above.
Not seeing 'Fix via pull request' on a resource you know is in Terraform?
Make sure the check type is in the supported list above, and that your Git connection is active (Settings → Integrations, look for Reconnect required). If the resource genuinely isn't in your connected repository or state, CostLens has nothing to map it to and falls back to the regular Apply Fix flow.