From tickets to pull requests: unifying infrastructure work
GitHub’s 2022 State of the Octoverse report showed HashiCorp Configuration Language (HCL)—the configuration language behind Terraform and Vault—as the fastest growing programming language on the platform. That growth signals something bigger than tool adoption: it points to a gradual merging of the traditionally separate worlds of infrastructure, operations, and software development.
DevOps has always aimed to bridge those gaps, but in practice many enterprises still run on siloed processes. The traditional operations model is built around shared services—security requirements, Active Directory, networking—and lines of business that consume them. Changes to infrastructure or architecture frequently require tickets across multiple teams, Change Advisory Board approvals, and manual governance documentation. The result is a slow, error-prone path to production.
Codifying infrastructure changes the dynamic. When infrastructure is defined as code, teams can apply the same collaboration patterns they use for applications: version control, peer review, automated checks, and auditable history. The outcome is a workflow where security and governance are baked in rather than bolted on at the end.
Infrastructure as a reusable blueprint
Think of Infrastructure as Code (IaC) as a blueprint for the resources that host your software. But just as you would not use the same blueprint for a hospital and a school, different workloads need different architectural patterns. What IaC provides—through HCL and Terraform—is the ability to define reusable building blocks that work across environments and use cases.
These building blocks can be shared, versioned, and maintained just like software libraries. Teams gain the benefits of DevOps methodologies: improved productivity, scalable cloud adoption, and better security practices.
Storing infrastructure in Git
Housing infrastructure code in GitHub provides a single source of truth with full version history. If a change breaks something, you can roll back or redeploy a known-good version. Git branches let teams work independently without affecting the main codebase, and pull requests become the natural mechanism for integrating changes.
Terraform modules—the reusable components of your infrastructure—are also stored and versioned in Git repositories. Tagging a release in GitHub can automatically update the module in Terraform Cloud’s private registry, making it discoverable across the organization.
Pull requests do more than merge code; they enable collaboration and peer review. Rather than waiting for a scheduled Change Advisory Board meeting, approvals happen inline with the proposed change. Reviewers can see the full context, leave comments, and approve or request changes directly in the workflow.
Branch protection rules can enforce that all changes to the main branch go through a pull request, with a minimum number of required reviewers. A CODEOWNERS file can automatically route review requests to the right people based on which files are being modified—for example, sending HCL changes to the core infrastructure team or configuration changes for a banking system to compliance.
Automated quality gates in the pipeline
Pull requests also open the door to automated quality checks. GitHub status checks can validate whether a proposed change meets defined criteria before it is merged. Common checks for IaC include:
- Syntax validation with
terraform validate - Code style and standards enforcement with tools like TFLint or
terraform fmt - Static analysis for misconfigurations using tools such as
tfsecorterrascan - Unit or integration tests with frameworks like Terratest
- Deployment to a smoke-test environment to confirm the configuration produces the expected state
Terraform is preinstalled on GitHub-hosted Linux runners, and HashiCorp’s official GitHub Action can set up a specific Terraform version for your workflow.
Compliance as code
Compliance testing and audit artifacts can be codified directly into HCL configurations. Policy as code extends this further: security and compliance teams can centralize organizational requirements using HashiCorp Sentinel or Open Policy Agent (OPA) frameworks. Terraform Cloud automatically ingests policy sets from GitHub repositories and applies them across every provisioning run, catching policy violations before misconfigurations reach production.
Keeping dependencies current automatically
Dependabot supports Terraform, so you can rely on automated dependency updates to keep provider and module versions current. This reduces the risk of running infrastructure on outdated or vulnerable code.
Shipping infrastructure through a review gate
Depending on your deployment strategy, GitHub Actions can carry the release process beyond testing and into production. Linux-based GitHub-hosted runners come with Terraform preinstalled, and HashiCorp also offers an official setup-terraform Action to pin a specific Terraform version per job. Branching and deployment models are outside this post's scope, but the GitHub-hosted tooling keeps the path from a validated branch to a live environment short.
A common Terraform practice is to run terraform plan to assess the effect of changes before they land, then terraform apply to execute them. With GitHub Actions, the output from plan can be posted directly into the pull request for review. This makes the "what will change in prod" discussion part of the code review itself.
Environments as approval boundaries
GitHub Actions environments map logically to deployment targets and can carry their own protection rules, including a required review before a release proceeds. You can separate planning from deployment by wiring each stage to its own environment.
name: 'Review and Deploy to EnvironmentA' on: [push] jobs: review: name: 'Terraform Plan' environment: environment_a_plan runs-on: ubuntu-latest steps: - name: 'Checkout' uses: actions/checkout@v2 - name: 'Terraform Setup' uses: hashicorp/setup-terraform@v2 with: cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} - name: 'Terraform Init' run: terraform init - name: 'Terraform Format' run: terraform fmt -check - name: 'Terraform Plan' run: terraform plan -input=false deploy: name: 'Terraform' environment: environment_a_deploy runs-on: ubuntu-latest needs: [review] steps: - name: 'Checkout' uses: actions/checkout@v2 - name: 'Terraform Setup' uses: hashicorp/setup-terraform@v2 with: cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} - name: 'Terraform Init' run: terraform init - name: 'Terraform Plan' run: terraform apply -auto-approve -input=false
In such a workflow, the planning stage runs against one environment, while the actual terraform apply targets environment_a_deploy. Because that environment is configured with an approval rule, no production change can be applied until a human explicitly approves it in the GitHub UI. The workflow you create can then be hardened with repository-level checks, keeping plan output and deploys in one auditable path.
For broader guidance, including recommended starting points for wiring Terraform Cloud into GitHub, HashiCorp publishes its Practitioner's Guide to Using HashiCorp Terraform Cloud with GitHub, and GitHub's own usage of Terraform is a documented case study.



