How to Integrate Terraform with Argo CD (Without Breaking GitOps)
Blake Pettersson

Why Terraform and Argo CD Together
Terraform provisions cloud infrastructure: Kubernetes clusters, databases, and identity or access controls. Argo CD deploys and manages the workloads that run on that infrastructure, following GitOps principles. Teams that adopt both tools eventually hit the same question: how does the output of Terraform's provisioning step become an input Argo CD can deploy from, without breaking Git's role as the source of truth? Three patterns have emerged to bridge Terraform and Argo CD:
The GitOps Bridge pattern — Terraform writes values into Kubernetes cluster Secrets as labels or annotations; an ApplicationSet with a cluster generator reads them.
A Git-based workflow for Helm — Terraform commits generated Helm values directly to Git; Argo CD reads them through a multi-source Application.
A Git-based workflow for Kustomize — the same Git-based approach, applied to generated Kustomize overlays instead of Helm values.
Pattern | Config source Argo CD reads | Review step | Works with |
|---|---|---|---|
GitOps Bridge | Cluster Secrets + Git | None built in | ApplicationSets (Helm) |
Git-based (Helm) | Git only | Pull request | Multi-source Applications |
Git-based (Kustomize) | Git only | Pull request | Multi-source Applications |
The Bridge pattern has real production traction — AWS maintains its own reference implementation through EKS Blueprints for Terraform, including examples for ingress, secrets management, and multi-cluster hub-and-spoke topologies. Still, the pattern splits configuration between Git and live cluster state. The Git-based approach keeps everything in Git and adds a pull-request review step, at the cost of managing feature branches and reconciling them with Terraform state.
What This Guide Covers
This guide walks through where the GitOps Bridge pattern falls short, then shows the Git-based workflow for both Helm and Kustomize step by step.
TL;DR
Teams using both Terraform and Argo CD need a way to pass Terraform's provisioned infrastructure values into Argo CD deployments without breaking Git as the source of truth.
The GitOps Bridge pattern stores Terraform values in cluster Secrets, read by an ApplicationSet — workable, but splits config between Git and live clusters.
A Git-based workflow keeps Terraform's output in Git instead, for both Helm values and Kustomize overlays.
Argo CD deploys only after a reviewer merges a pull request, adding a review step the Bridge pattern doesn't have.
Teams choosing the Git-based approach need to plan for feature branch cleanup and reconciling changes with Terraform state.
What Is the GitOps Bridge Pattern?
The GitOps Bridge pattern is a common design strategy for integrating Terraform with Argo CD. The approach stores Terraform-generated values in the Argo CD cluster Secret as labels or annotations. An ApplicationSet cluster generator reads the metadata and passes the configuration to an Argo CD Application.
The trade-off with the bridge pattern is that some deployment configuration lives in cluster metadata, reducing Git’s role as a complete record of the desired state.
The pattern has gained traction, including support from AWS, and works well for some teams. Terraform might provision an EKS cluster, create the IAM role ExternalDNS needs, and add the AWS account ID and IAM role name to the cluster Secret. Argo CD then reads those values and passes them to the ExternalDNS Helm chart.
A simplified but complete ApplicationSet might look like this:
The ApplicationSet extracts the account and role metadata from the cluster generator, then builds the required service account annotation. Pinning the chart to version 1.21.1 also prevents an upstream release from unexpectedly changing the deployment.
What Are the Limitations of the GitOps Bridge Pattern?
The GitOps Bridge pattern can introduce operational limitations by splitting deployment configuration between Git repositories and cluster Secrets. The implementation shown depends on the ApplicationSet cluster generator, complicates troubleshooting by placing some values in live cluster metadata, and requires additional steps for teams using Kustomize.
Teams using Terraform and Argo CD may encounter four main limitations with the GitOps Bridge pattern:
1. Creates an ApplicationSet Dependency
The implementation shown specifically requires an ApplicationSet with the cluster generator. Teams using standard Applications or other generator types need a different way to pass values into Argo CD.
2. Splits Deployment Inputs Across Git and Cluster Secrets
Argo CD deploys manifests from Git, but some configuration values come from cluster Secrets. Troubleshooting requires engineers to check both locations to understand the final deployment state.
3. Makes Inline Helm Configuration Difficult to Maintain
Inline Helm configurations can become large. Terraform can pass generated values directly into a Helm chart. However, the configuration becomes difficult to review and maintain as the number of parameters grows.
4. Adds Friction for Kustomize Users
The specific implementation shown relies on Helm value substitution. Teams using Kustomize must add a step to generate or patch files before Argo CD can build the overlay.
How Do You Integrate Terraform With Argo CD Through Git?
Terraform integrates with Argo CD through Git by generating Helm values or Kustomize overlays, committing them to a Git repository, and opening a pull request. Argo CD then reads the merged configuration from Git and deploys it.
The Terraform-to-Git workflow looks like this:
Terraform generates the configuration.
Terraform commits the file to Git.
A pull request provides a review step.
Argo CD reads the merged configuration and deploys it.
Terraform’s GitHub provider can create and update files directly in Git. It can also open pull requests. Git remains the deployment source Argo CD reads, while Terraform still owns and updates the generated file. Team members shouldn’t edit that file independently because Terraform may overwrite those changes during a later run.
To follow the walkthrough below, you'll need:
Terraform installed
A GitHub repository where Terraform can commit files
A fine-grained GitHub personal access token or GitHub App with Contents: read and write and Pull requests: read and write permissions on the repository
The GitHub Terraform Provider configured
Optionally, an existing multi-source Argo CD Application
The following steps use Helm, but the same approach works with umbrella charts or Kustomize.
Step 1: Define Helm Values in Terraform
Start by declaring your values in Terraform using a local block. These values will later be written to the Helm values file.
The server.retention value is supported by the Prometheus community Helm chart and changes how long Prometheus keeps collected metrics. In this example, the rendered deployment retains data for seven days rather than the chart’s 15-day default.
Step 2: Commit Helm Values to Git With Terraform
The GitHub provider’s github_repository_file resource lets you create or update files in a GitHub repository directly from Terraform, as long as the content is a string. The yamlencode() function converts the Terraform map into a YAML file that Helm can read.
Here’s how to create the Helm values file with github_repository_file:
Run terraform apply. This creates a commit in the tf-test GitHub repository with the values generated from Terraform. The overwrite_on_create option replaces an existing file if one is already present, so use it carefully. When working within a GitHub organization, define the organization in the Terraform provider configuration rather than prefixing the repository name.
Writing directly to main keeps the example simple, but many production repositories protect the default branch and require changes to go through a pull request instead. The next step shows that workflow.
Step 3: Reference Terraform-Generated Values in Argo CD
Now that the values file is in Git, you can reference it in an Argo CD multi-source Application. Here’s how to configure the Application:
The first source provides the Prometheus Helm chart. The second assigns the name "values" to the Git repository containing the Terraform-generated file, allowing "$values/main/values.yaml" to reference the same "main/values.yaml" path created in Step 2.
Step 4: Create a Feature Branch for Safer Changes
So far, Terraform is committing changes directly to main. In production, you’ll usually want a more controlled workflow.
Terraform can create a feature branch when the Helm values change, allowing you to open a pull request for review before merging anything into main.
If you already applied Step 2, do two things first. Change at least one value, for example, set retention to "10d" because GitHub will only open a pull request when the branch actually differs from main. Then remove the existing file from Terraform state:
terraform state rm github_repository_file.helm_values_example
Changing branch on github_repository_file forces replacement, and the destroy half of that replacement deletes the file from main, which breaks the Application from Step 3 until the pull request merges. Removing it from state leaves the main copy in place until the merge overwrites it.
The github_branch resource below creates a branch from main and names it using the first seven characters of a hash of the Helm values:
Because the branch name is based on the values content, each content change produces a new desired branch name.
Update the github_repository_file resource to commit to the feature branch:
Step 5: Open a Pull Request With Terraform
The GitHub provider includes a github_repository_pull_request resource that opens a pull request when you run terraform apply after creating the feature branch. This resource connects the newly created feature branch to the main branch, creating a review step before Argo CD deploys the merged updates.
Here’s the configuration to open the pull request:
When you run terraform apply, Terraform will:
Generate the Helm values
Create a feature branch
Commit the values to that branch
Open a pull request
Terraform opens the pull request but doesn’t merge it. A reviewer or separate automation must approve and merge the change. Protected branches may also require approvals, status checks, or other repository rules before GitHub allows the merge.
There are two behaviors to plan for. Because the branch name is derived from the values, changing them again before a merge replaces the branch, and deleting the old branch automatically closes its open pull request. After a merge, if the repository auto-deletes branches, the next apply recreates the branch and file from the new main. That's harmless, but it will show up in the plan output, and a new pull request won't open until the values change again.
Why Should I Use Git to Connect Terraform and Argo CD?
Using Git to connect Terraform and Argo CD provides a reviewable deployment workflow with pull-request approval, support for both Helm and Kustomize, and a complete deployment history in Git.
Feature | GitOps Bridge Pattern | Git-Based Workflow |
|---|---|---|
Deployment source | Argo CD reads config from Git and cluster Secrets. | Argo CD deploys manifests and values from Git only. |
Where generated values live | Terraform writes values into cluster Secrets as labels or annotations. | Terraform generates a values file and commits it to Git before deployment. |
Review process | No built-in review step; values apply directly to the cluster. | A reviewer approves changes through a pull request before merging. |
Helm support | Works with ApplicationSets using the cluster generator. | Works with multi-source Applications referencing a values file stored in Git. |
Kustomize support | Requires additional steps to generate or patch files before Argo CD builds the overlay. | Terraform can generate Kustomize overlays or patches that Argo CD deploys from Git. |
Operational trade-offs | Simpler for teams already using ApplicationSets and cluster generators at scale; splits config between Git and live cluster state. | Requires managing feature branches and pull requests, but keeps a single, auditable deployment history entirely in Git. |
Git-based workflows are also becoming more common across the cloud native ecosystem.
In the CNCF GitOps microsurvey, 71% of respondents ranked faster software delivery as the top reason for adopting GitOps, while 69% named the shift from manual processes to automation, which reduces the risk of misconfiguration, as its number-one security benefit.
We’ve seen those benefits in practice. We’ve used this pattern in production to generate Helm values and other deployment configuration with Terraform, commit the generated files through pull requests, and let Argo CD deploy only after the changes were reviewed. That removed the need to manage generated configuration in cluster Secrets while giving reviewers a clear Git history of every deployment change.
How Do You Integrate Terraform and Argo CD With Kustomize?
Generating Kustomize overlays with Terraform integrates Terraform and Argo CD through a Git-based workflow. Terraform commits the generated overlay files to Git, and Argo CD deploys the approved configuration from the repository. Here’s how:
Step 1: Define a Kustomize Overlay in Terraform
Just like with Helm values, define the overlay as a Terraform local object:
Step 2: Create a Branch for the Kustomize Overlay
Create a feature branch using the same pattern as the Helm example:
Step 3: Commit the Kustomize Overlay to Git
Encode the overlay as YAML and commit it to your Git repository:
Terraform generates the kustomization.yaml file and commits it to the repository, and Argo CD deploys it after the change is reviewed.
Step 4: Open a Pull Request for the Kustomize Changes
Open a pull request for the generated overlay:
Step 5: Reference the Kustomize Overlay in Argo CD
After the pull request is merged, reference the overlay in your Argo CD Application:
This example uses a generated Kustomize overlay, but the same workflow also works for generated patches and other Kustomize resources. Terraform generates the files, Git provides the review process, and Argo CD deploys the approved configuration.
What Does a Modern Terraform and Argo CD Workflow Look Like?
A modern Terraform and Argo CD workflow uses Terraform to generate configuration, Git to review and store it, and Argo CD to deploy the approved version. Each tool keeps a clear role in the process.
A Git-based Terraform and Argo CD workflow works well when pull-request review and support for both Helm and Kustomize are priorities. Anyone adopting this approach should also plan how to clean up branches and reconcile those changes with Terraform state. The existing GitOps Bridge pattern may still suit environments that rely on ApplicationSets and cluster-specific metadata.
These examples are a starting point, so review repository permissions, branch protections, and state-management requirements before using them in production.
Feel free to experiment with the examples or fork the Terraform and GitHub proof-of-concept repository. If you have questions, reach out on the Akuity Community Discord. You’ll find me there as Blake Pettersson.
Where Can I Learn More About Argo CD?
If you enjoyed this blog, be sure to check out other great resources on Argo CD:

