You version-control your infrastructure. You review pull requests for application code. But what about your FinOps configuration — your budgets, cost allocations, alerts, and analytics reports?
For most teams, these live in a UI. Someone clicks through a wizard, sets a threshold, picks a filter, and hopes the next person who needs to change it can figure out what was intended. There's no history, no peer review, and no way to replicate the setup across environments. When your FinOps practices are as critical as your infrastructure, they deserve the same rigor.
That's why we built the DoiT Terraform provider. It brings your DoiT Cloud Intelligence configuration into the same Infrastructure as Code workflow you already use for cloud resources — with 17 managed resources and 61 data sources covering everything from budgets and reports to AI assistant queries and cloud infrastructure diagrams.
Getting Started
Getting up and running takes just a provider block and an API key:
terraform { required_providers { doit = { source = "doitintl/doit" version = "~> 1.0" } }}
provider "doit" {}Set DOIT_API_TOKEN in your environment (you can create API keys in the DoiT Console), and you're ready to go. That's it — no additional configuration required.
The Core FinOps Workflow
Let's walk through the resources most teams reach for first: allocations, budgets, alerts, and reports. Together, they form a complete FinOps pipeline — and managing them as code means you can version, review, and replicate the entire setup.
Cost Allocations
Allocations are how you slice cloud spend into meaningful categories. The provider supports a boolean formula engine for combining filter criteria, group allocations that split costs into named buckets, and even nested allocations that reference other allocations by ID.
Here's a group allocation that splits costs by region, with a catch-all for anything that doesn't match:
resource "doit_allocation" "by_region" { name = "By Region" description = "Group costs by geographic region" unallocated_costs = "Other Regions" rules = [ { action = "create" name = "US" formula = "A" components = [{ key = "country", mode = "is", type = "fixed", values = ["US"] }] }, { action = "create" name = "Europe" formula = "A" components = [{ key = "country", mode = "is", type = "fixed", values = ["DE", "FR", "GB", "NL"] }] } ]}Need finer granularity? Use type = "allocation_rule" in a component to reference an existing allocation — composing allocations from other allocations, up to 3 levels deep. And instead of hardcoding dimension values like "US" or "DE", you can use the doit_dimension data source to discover valid values dynamically from the API.
Budgets
Budgets are the guardrails. The provider lets you define multi-threshold alerts, scope budgets to specific allocations or dimensions, and — here's a useful pattern — filter collaborators by job function rather than adding every user in the organization:
data "doit_users" "all" {}
locals { engineers = [ for u in data.doit_users.all.users : u if u.job_title == "Software / Ops Engineer" ]}
resource "doit_budget" "eng_budget" { name = "Engineering Budget" currency = "USD" type = "recurring" amount = 10000 time_interval = "month" start_period = provider::time::rfc3339_parse("2026-01-01T00:00:00Z") * 1000
alerts = [ { percentage = 50 }, { percentage = 80 }, { percentage = 100 } ]
collaborators = concat( [{ email = data.doit_current_user.me.email, role = "owner" }], [for u in local.engineers : { email = u.email, role = "viewer" }] )
recipients = [for u in local.engineers : u.email]
scopes = [{ type = "allocation_rule" id = "allocation_rule" mode = "is" values = [doit_allocation.by_region.id] }]}This budget scopes to the region allocation we just created, and only notifies users with the "Software / Ops Engineer" job title. Budgets also support seasonal_amounts for months where your spend targets vary, and computed fields like current_utilization and forecasted_utilization are available as read-only outputs.
Alerts
Alerts trigger notifications when cost or usage crosses a threshold. The real power here is scoping — you can narrow an alert to a specific cloud provider, service, region, or any dimension. This example uses the doit_products data source to dynamically look up the Compute Engine service ID instead of hardcoding it:
data "doit_products" "gcp" { platform = "google_cloud_platform"}
resource "doit_alert" "compute_cost" { name = "GCP Compute Cost Alert" config = { metric = { type = "basic", value = "cost" } time_interval = "day" value = 500 currency = "USD" condition = "value" operator = "gt" scopes = [{ type = "fixed" id = "service_description" mode = "is" values = [ for p in data.doit_products.gcp.products : p.id if p.display_name == "Compute Engine" ] }] } recipients = [data.doit_current_user.me.email]}Reports
Cloud Analytics reports are the most feature-rich resource in the provider. You can configure up to 4 metrics, add year-over-year comparisons with secondary_time_range, apply filters and group-by dimensions, and organize reports into folders.
resource "doit_report" "monthly_costs" { name = "Monthly Cost Report" description = "Tracks monthly costs across cloud providers with YoY comparison" config = { metrics = [ { type = "basic", value = "cost" }, { type = "basic", value = "usage" } ] aggregation = "total" time_interval = "month" data_source = "billing" time_range = { mode = "last" amount = 3 include_current = true unit = "month" } secondary_time_range = { amount = 1, unit = "year", include_current = false } filters = [{ id = "cloud_provider", type = "fixed", mode = "is" values = ["amazon-web-services", "google-cloud"] }] group = [{ id = "cloud_provider", type = "fixed" }] layout = "table" display_values = "actuals_only" currency = "USD" }}If you need to discover valid dimension IDs and types for filters and groupings, the doit_dimensions data source provides a complete catalog — no more guessing.
Beyond FinOps
The core FinOps resources are what most teams start with, but the provider covers significantly more of the DoiT platform. Some of these features you might not even know exist in the console — and managing them as code is a great way to discover them.
Ask Ava from Terraform
Yes, you can query Ava — DoiT's AI assistant — directly from your Terraform configuration. What makes this particularly useful is that you can reference report IDs from other Terraform resources in your prompt:
data "doit_ava" "report_summary" { question = "Can you summarize report ${doit_report.monthly_costs.id} for me?"}
output "report_summary" { value = data.doit_ava.report_summary.answer}Create a report, then immediately ask Ava to explain it — all in the same terraform apply. You can also use it for quick lookups like "What are my top 3 cloud services by cost this month?" and pipe the answer into Terraform outputs.
Ad-Hoc Analytics Queries
Sometimes you don't need a persisted report — you just need to answer a question. The doit_report_query data source runs Cloud Analytics queries on the fly and returns structured JSON that you can parse, transform, or export:
data "doit_report_query" "cost_by_provider" { config = { metrics = [{ type = "basic", value = "cost" }] aggregation = "total" time_interval = "month" currency = "USD" time_range = { mode = "last", amount = 3, include_current = true, unit = "month" } group = [{ id = "cloud_provider", type = "fixed" }] }}
locals { result = jsondecode(data.doit_report_query.cost_by_provider.result_json) columns = [for s in local.result.schema : s.name]}
resource "local_file" "query_csv" { filename = "cost_by_provider.csv" content = join("\n", concat( [join(",", local.columns)], [for row in local.result.rows : join(",", [for cell in row : cell == null ? "" : tostring(cell)])] ))}This is especially useful for CI/CD cost gates — run a query during your pipeline, check if spend exceeds a threshold, and fail the build if it does. You can also use doit_report_result to fetch results from existing saved reports.
Cloud Diagrams as Mermaid Flowcharts
The provider includes 12 data sources for the Cloud Diagrams feature, covering search, export, relationships, snapshots, and statistics. One creative use case: generating Mermaid flowcharts from your cloud infrastructure topology that you can embed directly in READMEs, Confluence pages, or incident reports.
data "doit_cloud_diagrams_search" "project" { query = "my-gcp-project"}
data "doit_cloud_diagrams_schemes" "diagram" { layer_ids = [data.doit_cloud_diagrams_search.project.scheme[0].ss_id] components = true link = true}
locals { ss = data.doit_cloud_diagrams_schemes.diagram.statussheet[ data.doit_cloud_diagrams_search.project.scheme[0].ss_id ]
node_lines = [ for id, n in local.ss.node : " ${id}[\"${replace(coalesce(n.name, id), "\"", "#quot;")}\"]" ]
edge_lines = [ for id, l in local.ss.link : l.connection_type != null ? " ${l.origin._id} -->|${l.connection_type}| ${l.destination._id}" : " ${l.origin._id} --> ${l.destination._id}" ]
mermaid = join("\n", concat(["flowchart LR"], local.node_lines, local.edge_lines))}
output "mermaid" { value = local.mermaid}Paste the output into mermaid.live or any Markdown renderer and you get a visual representation of your infrastructure relationships — topology diffs over time, compliance snapshots, or just a quick overview of what's connected to what.
Sharing & Access Control
Managing who can see your FinOps resources is often an afterthought — until it isn't. The doit_sharing resource lets you define permissions for reports, budgets, alerts, and allocations:
locals { permissions = [ { user = data.doit_current_user.me.email, role = "owner" }, ]}
resource "doit_sharing" "report" { resource_type = "reports" resource_id = doit_report.monthly_costs.id permissions = local.permissions public = "viewer" # Grant org-wide read access}Define your permission sets once in locals and apply them consistently across every shared resource. Pair this with doit_user to onboard new team members and doit_roles to discover available roles — all from your Terraform config.
Annotations & Labels
Ever looked at a cost spike from six months ago and wondered what happened? Annotations let you document cost events — deployments, migrations, incidents — directly on your cost data:
resource "doit_label" "infrastructure" { name = "infrastructure" color = "blue"}
resource "doit_annotation" "black_friday" { content = "AWS cost spike due to Black Friday traffic" timestamp = "2024-11-29T00:00:00Z" reports = [doit_report.monthly_costs.id] labels = [doit_label.infrastructure.id]}Labels and label assignments provide cross-resource tagging — categorize reports, alerts, and annotations by team, project, or any taxonomy that makes sense for your organization.
Organizing at Scale with Folders
As your Terraform-managed FinOps configuration grows, folders keep things tidy. They support nesting and work with both reports and allocations:
resource "doit_folder" "analytics" { name = "Analytics" description = "Cloud Analytics reports and dashboards"}
resource "doit_folder" "cost_reports" { name = "Cost Reports" description = "Monthly and quarterly cost breakdowns" parent_folder_id = doit_folder.analytics.id}
resource "doit_report" "monthly_costs" { name = "Monthly Cost Overview" folder_id = doit_folder.cost_reports.id # ... report config ...}You can also brand your analytics with custom themes — define light and dark mode color palettes that apply to Cloud Analytics report charts, giving your dashboards a polished, on-brand look.
AWS CloudConnect Onboarding
Connecting AWS accounts to DoiT is typically a multi-step process: create an IAM role, configure an S3 bucket, register the account. We've published a dedicated Terraform module that handles the entire stack in a single terraform apply:
module "doit_cloudconnect" { source = "doitintl/doit-cloudconnect/aws" version = "~> 1.0"}The module creates the IAM role, S3 bucket, and CloudConnect registration in one go. For enterprises onboarding dozens of accounts, use it with for_each over an account list. If you need more control, the underlying doit_cloudconnect_aws_account resource is available for direct use.
Custom Insights
If you're running your own optimization checks — scanning for unused resources, identifying rightsizing opportunities, flagging security issues — you can publish findings directly into the DoiT console:
resource "doit_insight" "unused_instances" { key = "unused-ec2-instances" title = "Unused EC2 Instances" short_description = "EC2 instances with consistently low CPU utilization" cloud_provider = "aws" categories = ["FinOps"]}Pair this with doit_insight_resource_results to attach per-resource findings, and your custom optimization engine surfaces results alongside DoiT's built-in insights.
The Composability Pattern
Across all of these examples, you'll notice a recurring theme: data sources are the glue. Instead of hardcoding dimension IDs, service names, or user emails, you discover them at plan time:
data "doit_dimensions" "all" {}
locals { dimension_types = { for id, types in { for d in data.doit_dimensions.all.dimensions : d.id => d.type... } : id => types[0] }}This dimension lookup map is reusable across reports, budgets, alerts, and allocations — write it once, reference local.dimension_types["region"] everywhere. Similarly, doit_current_user eliminates hardcoded emails, doit_products discovers valid service filter values, and doit_platforms lists the cloud providers available to your organization.
Actively Developed and Open Source
The provider has had 5 minor releases in the four months since v1.0 launched in February 2026, each adding new resources and data sources. Recent highlights include Cloud Diagrams support, custom console themes, folder management, sharing and access control, AWS CloudConnect onboarding, and the Ava AI data source.
If you're still on a v0.x release, now is a great time to upgrade. The v0.x versions were a technical preview — v1.x is the stable, production-ready line with automatic state migration to make the transition smooth. Check the v1.0.0 Upgrade Guide for migration instructions.
The provider is open source at github.com/doitintl/terraform-provider-doit. We welcome issues, feature requests, and contributions. Every resource has acceptance tests that run against the real DoiT API, and the CloudConnect AWS module is the first of planned higher-level modules that compose provider resources into ready-to-use patterns.
Get Started
- Install from the Terraform Registry
- Create an API key
- Browse the full documentation for schema details and more examples
- Star the GitHub repo and let us know what you'd like to see next
Your FinOps practices deserve the same version control, peer review, and reproducibility as your infrastructure. Give the provider a try and bring your cloud intelligence under code.