Claude Code works with GitLab through a CI/CD job: you add a job to .gitlab-ci.yml that installs Claude Code and runs claude -p with your instructions, store ANTHROPIC_API_KEY as a masked variable, and Claude can then implement changes and propose them as merge requests. The integration is in beta and is maintained by GitLab, not Anthropic.
This guide walks through the quick setup, how @claude mentions are wired up, cloud provider options, costs and common failures. It is based on the official Claude Code GitLab CI/CD docs. If you use GitHub instead, see Claude Code GitHub Actions.
What can Claude Code do in GitLab?
Inside a GitLab pipeline, Claude Code runs in your own runners, in a container, with your branch protection and approval rules still in force. According to the docs, it can:
- create and update merge requests from issue descriptions or comments
- implement features in a branch, then open an MR
- fix bugs and regressions found by tests or comments
- analyze performance regressions and propose optimizations
- respond to follow-up comments to iterate on requested changes
Every change flows through an MR, so reviewers see the diff and your normal approvals apply. Claude also reads your repository's CLAUDE.md during runs, so project conventions carry over from local use. The Claude Code memory guide covers what to put in that file.
Under the hood, the integration uses the same Claude Code CLI you run locally, in non-interactive mode. If you have already scripted Claude with -p, the GitLab job will look familiar; see the headless mode guide for the flags.
How do you set up Claude Code in GitLab CI/CD?
The quick setup takes two steps.
1. Add a masked CI/CD variable. In your project, go to Settings > CI/CD > Variables and add ANTHROPIC_API_KEY. Mark it masked, and protected if you only want it available on protected branches.
2. Add a Claude job to .gitlab-ci.yml. This is the minimal job from the official docs, with its comments removed:
stages:
- ai
claude:
stage: ai
image: node:24-alpine3.21
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
GIT_STRATEGY: fetch
before_script:
- apk update
- apk add --no-cache git curl bash
- curl -fsSL https://claude.ai/install.sh | bash
- export PATH="$HOME/.local/bin:$PATH"
script:
- /bin/gitlab-mcp-server || true
- echo "$AI_FLOW_INPUT for $AI_FLOW_CONTEXT on $AI_FLOW_EVENT"
- >
claude
-p "${AI_FLOW_INPUT:-'Review this MR and implement the requested changes'}"
--permission-mode acceptEdits
--allowedTools "Bash Read Edit Write mcp__gitlab"
--debug
A few lines are worth understanding before you copy this:
- The
rulesblock runs the job when you start a pipeline by hand from the web UI or when a merge request event fires. Change these to match how you want it to trigger. - The installer puts
claudein~/.local/bin, which is not on thePATHin this image, hence theexportline. --permission-mode acceptEditslets Claude edit files without stopping for approval, which a CI job cannot give anyway.--allowedToolslimits which tools it can use.- The
gitlab-mcp-serverline is optional and only does something if your setup provides a GitLab MCP server. The|| truekeeps the job running if it does not.
To test it, run the pipeline manually from CI/CD > Pipelines, or open a merge request.
For production, the docs recommend a more deliberate setup: store credentials as masked variables, use CI_JOB_TOKEN or a Project Access Token with api scope (saved as GITLAB_ACCESS_TOKEN) for GitLab API actions, and pick a provider job that fits your cloud.
How do @claude mentions work in GitLab?
The examples in the docs show comments like these on issues and merge requests:
@claude implement this feature based on the issue description
@claude suggest a concrete approach to cache the results of this API call
@claude fix the TypeError in the user dashboard component
The minimal job above does not listen to comments on its own. Mention triggers are an optional step you wire up:
- Add a project webhook for Comments (notes) that points to an event listener you run.
- When a comment contains
@claude, the listener calls GitLab's pipeline trigger API with variables such asAI_FLOW_INPUT(the request) andAI_FLOW_CONTEXT(where it came from). - The Claude job reads those variables and passes
AI_FLOW_INPUTtoclaude -p.
That is why the job uses ${AI_FLOW_INPUT:-...}: when the variable is present it becomes the prompt, and otherwise a default prompt runs. Note that the trigger word is @claude, not /claude.
Can you run it on Amazon Bedrock or Google Cloud?
Yes. The docs include full job examples for both, and neither stores long-lived cloud keys in GitLab.
| Provider | How the job authenticates | Key variables |
|---|---|---|
| Claude API | Masked API key | ANTHROPIC_API_KEY |
| Amazon Bedrock | GitLab OIDC token exchanged for temporary AWS credentials via an IAM role | AWS_ROLE_TO_ASSUME, AWS_REGION, CLAUDE_CODE_USE_BEDROCK=1 |
| Google Cloud's Agent Platform | Workload Identity Federation impersonating a service account | GCP_WORKLOAD_IDENTITY_PROVIDER, GCP_SERVICE_ACCOUNT, GCP_PROJECT_ID, CLOUD_ML_REGION, CLAUDE_CODE_USE_VERTEX=1 |
Both cloud jobs use GitLab's id_tokens: block to mint an OIDC token, exposed as GITLAB_OIDC_TOKEN, with aud set to the audience you configured on the cloud side. For Bedrock, restrict the IAM role's trust policy to your project and protected refs, and grant only Bedrock invoke permissions. Bedrock model IDs carry region prefixes, for example us.anthropic.claude-sonnet-4-6.
The cloud setup itself (OIDC provider, IAM role, workload identity pool) follows the same rules as running Claude Code against those providers locally, covered in Claude Code on Bedrock and Vertex.
What does Claude Code in GitLab CI cost?
There are two separate bills:
- GitLab runner time. Claude runs on your runners and uses compute minutes under your GitLab plan.
- Model tokens. Each run consumes tokens based on prompt size, response size, task complexity and codebase size, billed at Anthropic's API pricing or through your cloud provider.
The docs suggest three ways to keep costs down: write specific @claude requests so fewer turns are needed, set --max-turns and a job-level timeout (for example timeout: 30m), and limit how many Claude jobs run at once. Caching npm and package installs in your runners also shortens every job.
How do you keep the integration secure?
The official guidance is short and worth following exactly:
- Never commit API keys or cloud credentials to the repository. Use masked GitLab CI/CD variables.
- Prefer provider OIDC over long-lived keys wherever you can.
- Limit job permissions and network egress.
- Review Claude's merge requests like any other contributor's.
Keep --allowedTools as narrow as the job needs. A review-only job does not need Write, for example. The permissions guide explains how tool rules work.
Why is Claude not responding in GitLab?
The docs list three common failure groups.
Claude does not respond to @claude. Check that a pipeline actually started (manually, from an MR event, or through your webhook listener), that ANTHROPIC_API_KEY or your cloud variables are set, and that the comment says @claude.
The job cannot comment or open MRs. Make sure CI_JOB_TOKEN has enough permission on the project, or switch to a Project Access Token with api scope. Confirm mcp__gitlab is in --allowedTools, and that the job has MR context or enough information through the AI_FLOW_* variables.
Authentication errors. For the Claude API, check the key is valid. For Bedrock or Agent Platform, verify the OIDC or Workload Identity setup, role impersonation, variable names, region and model availability.
Because the integration is in beta, flags can change between versions. Running claude --help inside the job shows what your installed version supports. For support, the Claude Code docs point to this GitLab issue.
Reuse the same instructions locally and in CI
The prompts you pass with -p in CI are worth keeping as carefully as code. Kipt stores prompts and Agent Skills as Markdown in a private GitHub repo you own, with {{name}} blanks for the parts that change, so the review or implementation prompt you refine at your desk is the same one your pipeline jobs use.