Cloudflare and HashiCorp: A Deeper Terraform Integration
Cloudflare's relationship with HashiCorp dates back to 2018, and over the years the two companies have steadily expanded their technical collaboration. The centerpiece of that work has been Terraform, HashiCorp's infrastructure-as-code tool. Today, Cloudflare is announcing a significant update to cf-terraforming, its tool for bootstrapping Terraform configurations from existing Cloudflare resources.
The announcement builds on the existing HashiCorp Terraform Verified Provider for Cloudflare, which has been the foundation for managing Cloudflare resources declaratively. With the new version of cf-terraforming, the goal is to lower the barrier to entry for developers who want to adopt Terraform but face the initial hurdle of converting their existing infrastructure into code.
What cf-terraforming Does
cf-terraforming is designed to solve a common problem: you have Cloudflare resources already deployed through the dashboard or API, and you want to manage them with Terraform. Manually writing the corresponding HCL configuration for every DNS record, firewall rule, or load balancer is tedious and error-prone. The tool automates this by importing those live resources and generating the required Terraform configuration files.
The original version of cf-terraforming relied on Terraform's import command, which requires the configuration to exist beforehand. This created a chicken-and-egg problem: you still needed to write the HCL to import the resource. The new release removes that friction by fetching resource definitions directly from the Cloudflare API and generating the HCL for you, without requiring any prior configuration.
How the New Version Works
The updated cf-terraforming connects to your Cloudflare account via API credentials and enumerates resources across your zones and account-level services. It then produces Terraform configuration files in the correct provider schema, so you can apply them immediately. This is particularly valuable for teams with large, sprawling Cloudflare setups where manual conversion would take days.
One key difference in this release is the output format. The tool now generates resources in a way that aligns with the Terraform provider's expected syntax, meaning the generated code is more likely to work out of the box. There is also support for generating import blocks, allowing you to bring existing resources under Terraform management without downtime.
Cloudflare positions this as a step toward making their platform more accessible to infrastructure-as-code practitioners. By closing the gap between "already running in Cloudflare" and "defined in Terraform", the company hopes more users will adopt the declarative workflow and benefit from version control, code review, and automated provisioning.
Getting Started
The tool is available as a binary you can run locally or incorporate into a CI/CD pipeline. To begin, you install cf-terraforming, set your Cloudflare API token, and point it at the zone or account you want to convert. The generated output can be inspected, modified, and then applied using the standard Terraform workflow.
Cloudflare has provided documentation and examples for common use cases, including DNS, Page Rules, and firewall settings. The project remains open source on GitHub, and the company encourages contributions from the community to expand supported resource types and improve the output quality.
For teams already invested in HashiCorp's ecosystem, this update makes it significantly easier to bring Cloudflare under the same infrastructure-as-code umbrella as other cloud providers. The partnership between the two vendors continues to mature, and the tooling reflects that shared direction.
Cloudflare and HashiCorp partnership
Cloudflare’s Terraform provider began as a community effort, but customer demand quickly pushed it to become a first-class, officially supported product. Today the provider is “verified” by HashiCorp, and the two companies work together to keep the developer experience solid.
Terraform itself has become the standard way to manage infrastructure-as-code across clouds, containers, and service providers. It uses HashiCorp Configuration Language (HCL) to let teams treat infrastructure like software: commit configurations to git, review changes, track versions, and roll back when deployments go wrong.
Our developers love the power of Cloudflare + Terraform for infrastructure provisioning. IT operations teams want a platform that provides complete visibility and control... Cloudflare + Terraform platform provides just that.– Dmitry Zadorojnii, Chief Technology Officer, Autodoc GmbH
Since the provider’s 1.0 release, Cloudflare has expanded the resources it exposes, while HashiCorp has built out the ecosystem around it. The Terraform Registry gives developers a central place to find provider documentation, and Terraform’s own v0.12 release brought major changes to how configurations are written and validated.
Leveraging the power of Terraform, you can codify your Cloudflare configuration. Codification enables version control and automation, increasing productivity and reducing human error.– Asvin Ramesh, Director, Technology Alliances, HashiCorp
A new approach in cf-terraforming
Cloudflare first released cf-terraforming in early 2019. The tool was inspired by dtan4’s terraforming project, which solved the same problem for AWS: how do you take an existing, fully-configured environment and bootstrap it into Terraform without hand-writing every resource?
Terraform expects to be the sole authority over the infrastructure it manages. That works fine for greenfield deployments, but existing customers who configured everything through dashboards or APIs face a painful migration. Before cf-terraforming, moving to Terraform meant writing configuration for every object and running terraform import for each one individually — an impractical approach for large deployments.
The tool provided two key outputs: tfconfig files describing the resources and tfstate files holding their current state. That made it possible for DoorDash, for example, to port thousands of DNS records into a Git-ops workflow:
cf-terraforming was one of the enabling technologies that we used to bootstrap Cloudflare into our Terraform Git-ops workflow... Using cf-terraforming to generate our initial set of resources allowed our engineers to submit Cloudflare changes, enabling our product engineers to be infrastructure operators.– Sean Chittenden, Infrastructure, DoorDash
What needed to change
Maintaining cf-terraforming revealed three structural problems. First, whenever Cloudflare added a new API feature, changes had to ripple through three codebases: the cloudflare-go library, the Terraform provider, and cf-terraforming itself. Any missed update meant the tool could produce incomplete or broken configurations. Second, major Terraform releases like the 0.12 overhaul required careful coordination and testing across all three layers. And third, the tool’s attempt to generate tfstate files directly pulled it into the internals of Terraform’s state format — implementation details that the team ultimately decided it shouldn’t own.
The new version of cf-terraforming addresses all three issues by leaning on Terraform’s own tooling. It now uses terraform-exec to fetch the provider’s JSON schema via terraform providers schema -json. Since API response fields often map one-to-one onto schema fields, the tool can auto-generate configuration for most resources with only minor tweaks. When the provider changes, regenerating the schema is enough — no manual code updates required.
Instead of attempting to synthesize tfstate content, the new version outputs the full set of terraform import commands that need to run for the selected resources. Since import commands don’t change when the Cloudflare API or provider evolves, this eliminates a whole category of maintenance work.
Bootstrapping an existing zone with cf-terraforming
To see the workflow in action, assume you have an existing Cloudflare zone with DNS records, firewall rules, and filters configured. You want to manage that zone in Terraform without redefining everything by hand.
You’ll need Terraform installed and Go v1.12.x or newer. First, generate an API token from the Cloudflare dashboard with read permissions for Zone:DNS and Zone:Firewall Services, scoped to the zone you want to manage. Setting a TTL on the token is a good safety habit.

Set the token as an environment variable, then create a working directory with a cloudflare.tf file containing the provider configuration:
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
}
}
}
provider "cloudflare" {
# api_token = "" ## Commented out as we are using an environment var
}
Run terraform init to install the provider, then install cf-terraforming:
$ GO111MODULE=on go get -u github.com/cloudflare/cf-terraforming/...
On macOS with Homebrew, the install is simpler:
$ brew tap cloudflare/cloudflare
$ brew install --cask cloudflare/cloudflare/cf-terraforming
Generating configuration
Start by generating the HCL for DNS records and appending it to cloudflare.tf:
cf-terraforming generate --resource-type cloudflare_record --zone <zone_id> >> cloudflare.tf
The command takes three arguments: generate produces valid HCL; --resource-type selects the Terraform resource (only one at a time, e.g. cloudflare_record); --zone provides the zone ID to query.
Without the >> cloudflare.tf redirect, the output appears in the console. Resources are named terraform_managed_resource_<resource_id>, which keeps names consistent between config and state during import. Repeat the process for cloudflare_firewall_rule and its associated filter resources:
cf-terraforming generate --resource-type cloudflare_firewall_rule --zone <zone_id> >> cloudflare.tf
cf-terraforming generate --resource-type cloudflare_filter --zone <zone_id> >> cloudflare.tf
Importing state
Now use the import command to generate the terraform import commands for each resource type:
cf-terraforming import --resource-type cloudflare_record --zone <zone_id>
The arguments mirror the generate command. The output is a ready-to-run import command for each resource, which populates the terraform.tfstate file without having to manually collect resource IDs from the API.
Order matters here: Terraform requires the configuration to exist in the .tf file before importing state. Also note that once a resource is imported, Terraform considers itself the source of truth — removing it later requires manual edits to the state file (though Terraform keeps backups).
$ terraform import cloudflare_record.terraform_managed_resource_47581f47852ad2ba61df90b15933903d 9c2f972575d986b99fa03c7bbfaab414/47581f47852ad2ba61df90b15933903d
cloudflare_record.terraform_managed_resource_47581f47852ad2ba61df90b15933903d: Importing from ID "9c2f972575d986b99fa03c7bbfaab414/47581f47852ad2ba61df90b15933903d"...
cloudflare_record.terraform_managed_resource_47581f47852ad2ba61df90b15933903d: Import prepared!
Prepared cloudflare_record for import
cloudflare_record.terraform_managed_resource_47581f47852ad2ba61df90b15933903d: Refreshing state... [id=47581f47852ad2ba61df90b15933903d]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
After the DNS records are imported, run the same import commands for firewall rules and filters.
Verifying the bootstrap
With both configuration and state in place, run terraform plan. A successful migration returns the familiar “no changes” message, confirming Terraform can reconcile the config with the actual Cloudflare resources.
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
You can now manage these resources entirely through Terraform. To bring more resources under management, repeat the process with their respective resource types — see the cf-terraforming README for the list of supported resources, and file GitHub issues to request others.



