Tutorial
Integrating Infracost with GitLab CI: Your Guide to Cost-Aware Merge Requests
If you're a GitLab user, this guide is for you. It's a straightforward, step-by-step tutorial on how to set up Infracost in your GitLab CI/CD pipeline. You'll learn how to get automatic cost estimates posted directly into your merge requests, making it easy to catch budget-busting changes.
Integrating Infracost with GitLab CI: Your Guide to Cost-Aware Merge Requests

For teams using GitLab for their source code management and CI/CD, integrating cost visibility into the development workflow is a crucial step toward mature FinOps practices. By showing the cost impact of infrastructure changes directly within a merge request (MR), you empower engineers to make cost-conscious decisions and prevent budget surprises before code is merged. Infracost provides a straightforward integration with GitLab CI to achieve exactly this.

This guide will walk you through the step-by-step process of configuring your .gitlab-ci.yml file to run Infracost and post automated cost estimate comments in your GitLab merge requests.

Prerequisites: API Keys and Tokens

Before you configure your CI/CD pipeline, you need to set up two essential credentials and store them as secure CI/CD variables in your GitLab project.

  1. Infracost API Key: Infracost uses a free API key to fetch up-to-date cloud pricing information. If you don't have it, install the Infracost CLI and run infracost auth login to register and get your key. Retrieve your key by running infracost configure get api_key. In your GitLab project, go to Settings > CI/CD and expand the Variables section. Add a new variable named INFRACOST_API_KEY, paste your key as the value, and ensure it is "Masked" for security. Uncheck the "Protect variable" option so it can be used on all branches, including feature branches for MRs.

  2. GitLab Token: Infracost needs a GitLab token with API access to post comments on your merge requests. Create a Project Access Token by navigating to Settings > Access Tokens. Give the token a name (e.g., infracost-ci), select the Maintainer role, and enable the api scope. Copy the generated token immediately. Return to the CI/CD Variables section and add a new variable named GITLAB_TOKEN. Paste the access token as the value, mask it, and uncheck the "Protect variable" box.

Configuring Your .gitlab-ci.yml File

With the variables in place, you can now define the CI/CD jobs in your .gitlab-ci.yml file. The following configuration uses a multi-stage approach to generate a cost baseline, calculate the difference, and post a comment to the merge request. This example assumes your Terraform code is in a subdirectory. You'll need to set a TF_ROOT variable to point to its location.

YAML

variables:
  # Set this to the relative path of your Terraform code
  TF_ROOT: 'path/to/your/terraform_code'

stages:
  - infracost

infracost:
  stage: infracost
  image:
    name: infracost/infracost:ci-0.10
    entrypoint: [""]
  script:
    # 1. Clone the target branch (e.g., main) to create a cost baseline
    - git clone $CI_REPOSITORY_URL --branch=$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --single-branch /tmp/base
    # 2. Generate an Infracost JSON file from the baseline
    - infracost breakdown --path=/tmp/base/${TF_ROOT} \
                        --format=json \
                        --out-file infracost-base.json
    # 3. Generate an Infracost diff against the baseline
    - infracost diff --path=${TF_ROOT} \
                     --compare-to infracost-base.json \
                     --format=json \
                     --out-file=infracost.json
    # 4. Post the comment to the merge request
    - infracost comment gitlab --path=infracost.json \
                               --repo=$CI_PROJECT_PATH \
                               --merge-request=$CI_MERGE_REQUEST_IID \
                               --gitlab-server-url=$CI_SERVER_URL \
                               --gitlab-token=$GITLAB_TOKEN \
                               --behavior update
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

How the GitLab CI Job Works

This configuration defines a single job named infracost that runs only for merge request events. Let's break down the script commands:

  1. Clone Target Branch: The pipeline first clones the target branch of the merge request (e.g., main or develop) into a temporary directory. This code represents the "before" state of your infrastructure and is used to generate a cost baseline.

  2. Generate Baseline: It then runs infracost breakdown on the cloned target branch code. The --format=json and --out-file flags save the cost snapshot to a file named infracost-base.json.

  3. Generate Diff: Next, the job runs infracost diff on the code from the MR's source branch (the current working directory). The --compare-to flag points to the baseline file, instructing Infracost to calculate the difference between the "before" and "after" states. This difference is saved to infracost.json.

  4. Post Comment: Finally, the infracost comment gitlab command is executed. It uses the generated diff file and several GitLab predefined CI/CD variables ($CI_PROJECT_PATH, $CI_MERGE_REQUEST_IID, etc.) to identify the correct merge request. The --gitlab-token=$GITLAB_TOKEN flag uses the secure variable you configured to authorize the API call. The --behavior update flag ensures that a single comment is created and updated on subsequent pushes to the MR, preventing notification spam.

Testing and Verifying the Integration

Once you commit the .gitlab-ci.yml file, the integration is live. To test it:

  1. Create a new feature branch from your main branch.

  2. Make a cost-impacting change to a .tf file within the directory specified by TF_ROOT. For example, change an instance size or add a new resource.

  3. Commit the change and open a new merge request.

Navigate to the merge request in the GitLab UI. You will see the infracost pipeline job running. Once it completes successfully, a comment from Infracost will appear in the MR's discussion thread, detailing the monthly cost increase or decrease resulting from your changes.

Advanced Use Cases and Considerations

The setup above covers the most common scenario, but the Infracost GitLab integration is flexible enough to handle more complex setups.

  • Terragrunt Projects: Infracost automatically detects Terragrunt projects. The same CI configuration can be used, but you may need to adjust the TF_ROOT variable to point to the root of your Terragrunt repository.

  • Monorepos with Multiple Projects: For repositories containing multiple, independent Terraform projects, you can use an infracost.yml configuration file to define each project. Infracost will then generate a combined report in the merge request comment.

  • Policy Enforcement: You can extend this pipeline to enforce cost policies. By integrating with Open Policy Agent (OPA) or Sentinel, you can configure the CI job to fail if a change violates a predefined budget or governance rule, effectively blocking costly merges.

  • Docker Images: The example uses infracost/infracost:ci-0.10. It is best practice to use a versioned image (e.g., ci-0.10) rather than ci-latest to prevent unexpected breaking changes in your pipeline.

Conclusion

By integrating Infracost into your GitLab CI pipeline, you embed cost awareness directly into your team's existing workflow. This simple automation provides a powerful feedback loop, transforming merge requests into a forum for discussing not just code quality and functionality, but also financial impact. This proactive approach to FinOps helps eliminate surprises on your cloud bill, fosters a culture of cost accountability, and ultimately leads to more efficient and sustainable cloud infrastructure.

See, Understand, Optimize -
All in One Place

Atler Pilot decodes your cloud spend story by bringing monitoring, automation, and intelligent insights together for faster and better cloud operations.