Skip to main content

GitLab CI

Run Infracost in GitLab CI to post cloud cost estimates and FinOps best practices on every merge request.

tip

The GitLab App needs no pipeline configuration and is the recommended path. Use this page when you need the estimate to run inside your own pipeline.

1. Add the two variables​

Under Settings → CI/CD → Variables, add both as Masked:

VariableValue
INFRACOST_CLI_AUTHENTICATION_TOKENYour Infracost CLI token
GITLAB_TOKENAn access token with api scope
caution

Do not tick Protected. Merge request branches are not protected, so a protected variable never reaches the job and the run fails with a missing token.

CI_JOB_TOKEN cannot post merge request notes, so it is deliberately not a fallback. A project or group access token is ideal. One group setting disables both, and its error names the group even on a project. If token creation is disabled, use a personal access token with api scope from a user with Developer or above.

2. Add the job​

infracost:
image: ghcr.io/infracost/ci:2
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
# Full history: the shallow default may not contain the target branch.
GIT_DEPTH: 0
script:
# GIT_STRATEGY=fetch reuses the build directory: git clean deletes the
# worktree directories but leaves them registered.
- git worktree prune
- git fetch origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- git worktree add base "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- git worktree add head HEAD
- infracost-ci diff --base-path base --head-path head

That is the whole integration. diff takes two checkouts of the same repository, computes the cost difference, posts or updates the merge request note, and uploads the run to Infracost Cloud.

The project URL, merge request IID, branches, title, labels and pipeline id all come from GitLab's own variables. No Terraform binary and no plan file: the parsers read your infrastructure code directly.

GitLab has no predefined variable for the merge request author, so diff reads it from the merge request with the same GITLAB_TOKEN it comments with. Without a token it falls back to CI_COMMIT_AUTHOR, whoever wrote the last commit. Set INFRACOST_VCS_PULL_REQUEST_AUTHOR to override either.

3. Track your default branch​

Add a second job so Infracost Cloud keeps baseline costs and issues current. This populates Issue Explorer and Visibility → Repos.

infracost-baseline:
image: ghcr.io/infracost/ci:2
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- infracost-ci scan --path .

scan takes a single directory, unlike diff.

4. Report merged merge requests​

Infracost Cloud calculates cost prevention (money saved by changes made before merging) from merged merge requests. GitLab pipelines do not trigger on a merge event, so read the merge commit on the default branch:

infracost-status:
image: ghcr.io/infracost/ci:2
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
variables:
GIT_DEPTH: 0
script:
- MR=$(git log -1 --pretty=%B | grep -oE 'See merge request .+![0-9]+' | grep -oE '[0-9]+$') || true
- '[ -n "$MR" ] && infracost-ci status --status MERGED --pr-number "$MR" || echo "no merge request in the commit message"'
caution

Fast-forward merges and customized merge commit templates break the pattern match. The merge request simply won't get merged status; nothing else fails.

Self-managed GitLab​

Nothing extra is needed: the server URL is derived from CI_PROJECT_URL.

A GitLab served from a relative root, https://host/gitlab/group/repo, needs --gitlab-server-url and --gitlab-project. For a private certificate authority, point INFRACOST_CI_VCS_TLS_CA_CERT_FILE at a PEM bundle.

Guardrails and blocking​

Guardrails and policies evaluate on every run. When one blocks, the note posts first and then diff exits 1, so the pipeline goes red with the reason already on the merge request. An unblock from the dashboard takes effect on the next run.

A red pipeline does not stop a merge on its own. To block one, turn on Settings → Merge requests → Pipelines must succeed.

Your code stays local​

Code is parsed inside the runner. Only the cost estimate and the merge request metadata reach Infracost Cloud.