<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://about.gitlab.com/blog</id>
    <title>GitLab</title>
    <updated>2026-04-28T19:30:33.801Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <author>
        <name>The GitLab Team</name>
    </author>
    <link rel="alternate" href="https://about.gitlab.com/blog"/>
    <link rel="self" href="https://about.gitlab.com/atom.xml"/>
    <subtitle>GitLab Blog RSS feed</subtitle>
    <icon>https://about.gitlab.com/favicon.ico</icon>
    <rights>All rights reserved 2026</rights>
    <entry>
        <title type="html"><![CDATA[How to build CI/CD observability at scale]]></title>
        <id>https://about.gitlab.com/blog/how-to-build-ci-cd-observability-at-scale/</id>
        <link href="https://about.gitlab.com/blog/how-to-build-ci-cd-observability-at-scale/"/>
        <updated>2026-04-28T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>CI/CD optimization starts with visibility. Building a successful DevOps platform at enterprise scale <strong>should include</strong> understanding pipeline performance, job execution patterns, and quantifiable operational insights — especially for organizations running GitLab self-managed instances.</p><p>To help GitLab customers maximize their platform investments, we developed the GitLab CI/CD Observability solution as part of our Platform Excellence program, which transforms raw pipeline metrics into actionable operational insights.</p><p>A leading financial services organization partnered with GitLab&#39;s customer success architect to gain visibility into their GitLab self-managed deployment. Together, we implemented a containerized observability solution combining the open-source gitlab-ci-pipelines-exporter with enterprise-grade Prometheus and Grafana infrastructure.</p><p>In this article, you&#39;ll learn the challenges they faced managing pipelines at scale and how GitLab CI/CD Observability addressed them with a practical, end-to-end implementation.</p><h2 id="the-challenge-measuring-cicd-performance">The challenge: Measuring CI/CD performance</h2><p>Before implementing any observability solution, define your measurement landscape:</p><ul><li><strong>What metrics matter?</strong> Pipeline duration, job success rates, queue times, runner utilization</li><li><strong>Who needs visibility?</strong> Developers, DevOps engineers, platform teams, leadership</li><li><strong>What decisions will this drive?</strong> Infrastructure investment, bottleneck remediation, capacity planning</li></ul><h2 id="solution-architecture-a-full-set-of-dashboards-for-observability">Solution architecture: A full set of dashboards for observability</h2><p>Once deployed, the observability stack provides a set of Grafana dashboards that give real-time and historical visibility into your CI/CD platform. A typical deployment includes:</p><ul><li><strong>Pipeline Overview Dashboard:</strong> A top-level view showing total pipeline runs, success/failure rates over time (as stacked bar or time-series charts), and average pipeline duration trends. Panels use color-coded status indicators (green for success, red for failure, amber for cancelled) so platform teams can spot degradation at a glance.</li><li><strong>Job Performance Dashboard:</strong> Drill-down panels showing individual job duration distributions (histogram), the top 10 slowest jobs by average duration, and job failure heatmaps by project and stage. This is where teams identify specific bottleneck jobs worth optimizing.</li><li><strong>Runner &amp; Infrastructure Dashboard:</strong> Combines Node Exporter host metrics (CPU, memory, disk) with pipeline queue-time data to correlate infrastructure saturation with pipeline wait times. Useful for capacity planning decisions such as scaling runner pools or upgrading instance sizes.</li><li><strong>Deployment Frequency Dashboard:</strong> Tracks deployment count and deployment duration over time per environment, aligned with DORA metrics. Helps engineering leadership assess delivery throughput and environment drift (commits behind main).</li></ul><p>Each dashboard is provisioned automatically via Grafana&#39;s file-based provisioning, so it deploys consistently across environments. The dashboards can be further customized with Grafana variables to filter by project, ref/branch, or time range.</p><p><img alt="Solution architecture" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1777382608/Blog/Imported/blog-building-ci-cd-observability-stack-for-gitlab-self-managed/image1.png" /></p><p>The solution requires two exporters:</p><ul><li><strong>Pipeline Exporter:</strong> Collects CI/CD metrics via GitLab API (pipeline duration, job status, deployments)</li><li><strong>Node Exporter:</strong> Collects host-level metrics (CPU, memory, disk) for infrastructure correlation</li></ul><p><strong>Prerequisites:</strong></p><ul><li>GitLab Self-Managed Version 18.1+</li><li><strong>Container orchestration platform:</strong> A Kubernetes cluster (recommended for enterprise deployments) or a container runtime such as Docker/Podman for smaller scale or proof-of-concept environments. The primary deployment guide below targets Kubernetes; a Docker Compose alternative is provided in the appendix for local testing and evaluation</li><li>GitLab Personal Access Token (<strong>read_api</strong> scope)</li></ul><h2 id="kubernetes-deployment-recommended">Kubernetes deployment (recommended)</h2><p>For enterprise environments, deploy each component as a separate Deployment within a dedicated namespace. This approach integrates with existing cluster infrastructure, secrets management, and network policies.</p><h3 id="_1-create-namespace-and-secret">1. Create namespace and secret</h3><pre className="language-bash shiki shiki-themes github-light" code="kubectl create namespace gitlab-observability

# Create the GitLab token secret (see Secrets Management section below
# for enterprise-grade approaches using external secret operators)
kubectl create secret generic gitlab-token \
  --from-literal=token=glpat-xxxxxxxxxxxx \
  -n gitlab-observability
" language="bash" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> create</span><span style="--shiki-default:#032F62"> namespace</span><span style="--shiki-default:#032F62"> gitlab-observability
</span></span><span class="line" line="2"><span emptyLinePlaceholder>
</span></span><span class="line" line="3"><span style="--shiki-default:#6A737D"># Create the GitLab token secret (see Secrets Management section below
</span></span><span class="line" line="4"><span style="--shiki-default:#6A737D"># for enterprise-grade approaches using external secret operators)
</span></span><span class="line" line="5"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> create</span><span style="--shiki-default:#032F62"> secret</span><span style="--shiki-default:#032F62"> generic</span><span style="--shiki-default:#032F62"> gitlab-token</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="6"><span style="--shiki-default:#005CC5">  --from-literal=token=glpat-xxxxxxxxxxxx</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="7"><span style="--shiki-default:#005CC5">  -n</span><span style="--shiki-default:#032F62"> gitlab-observability
</span></span></code></pre><h3 id="_2-deploy-the-pipeline-exporter">2. Deploy the Pipeline Exporter</h3><pre className="language-yaml shiki shiki-themes github-light" code="# exporter-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitlab-ci-pipelines-exporter
  namespace: gitlab-observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gitlab-ci-pipelines-exporter
  template:
    metadata:
      labels:
        app: gitlab-ci-pipelines-exporter
    spec:
      containers:
        - name: exporter
          image: mvisonneau/gitlab-ci-pipelines-exporter:latest
          ports:
            - containerPort: 8080
          env:
            - name: GCPE_GITLAB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: gitlab-token
                  key: token
            - name: GCPE_CONFIG
              value: /etc/gcpe/config.yml
          volumeMounts:
            - name: config
              mountPath: /etc/gcpe
      volumes:
        - name: config
          configMap:
            name: gcpe-config
---
apiVersion: v1
kind: Service
metadata:
  name: gitlab-ci-pipelines-exporter
  namespace: gitlab-observability
spec:
  selector:
    app: gitlab-ci-pipelines-exporter
  ports:
    - port: 8080
      targetPort: 8080
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># exporter-deployment.yaml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">apps/v1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Deployment
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-ci-pipelines-exporter
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  replicas</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">1
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">    matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">      app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-ci-pipelines-exporter
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">  template</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">    metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">      labels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">        app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-ci-pipelines-exporter
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">    spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="17"><span style="--shiki-default:#22863A">      containers</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">exporter
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">          image</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">mvisonneau/gitlab-ci-pipelines-exporter:latest
</span></span><span class="line" line="20"><span style="--shiki-default:#22863A">          ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="21"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">containerPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">8080
</span></span><span class="line" line="22"><span style="--shiki-default:#22863A">          env</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="23"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">GCPE_GITLAB_TOKEN
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">              valueFrom</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">                secretKeyRef</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="26"><span style="--shiki-default:#22863A">                  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-token
</span></span><span class="line" line="27"><span style="--shiki-default:#22863A">                  key</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">token
</span></span><span class="line" line="28"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">GCPE_CONFIG
</span></span><span class="line" line="29"><span style="--shiki-default:#22863A">              value</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/etc/gcpe/config.yml
</span></span><span class="line" line="30"><span style="--shiki-default:#22863A">          volumeMounts</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="31"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">config
</span></span><span class="line" line="32"><span style="--shiki-default:#22863A">              mountPath</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/etc/gcpe
</span></span><span class="line" line="33"><span style="--shiki-default:#22863A">      volumes</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="34"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">config
</span></span><span class="line" line="35"><span style="--shiki-default:#22863A">          configMap</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="36"><span style="--shiki-default:#22863A">            name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gcpe-config
</span></span><span class="line" line="37"><span style="--shiki-default:#6F42C1">---
</span></span><span class="line" line="38"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">v1
</span></span><span class="line" line="39"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Service
</span></span><span class="line" line="40"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="41"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-ci-pipelines-exporter
</span></span><span class="line" line="42"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="43"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="44"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="45"><span style="--shiki-default:#22863A">    app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-ci-pipelines-exporter
</span></span><span class="line" line="46"><span style="--shiki-default:#22863A">  ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="47"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">8080
</span></span><span class="line" line="48"><span style="--shiki-default:#22863A">      targetPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">8080
</span></span></code></pre><h3 id="_3-deploy-node-exporter-daemonset">3. Deploy Node Exporter (DaemonSet)</h3><pre className="language-yaml shiki shiki-themes github-light" code="# node-exporter-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: gitlab-observability
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      containers:
        - name: node-exporter
          image: prom/node-exporter:latest
          ports:
            - containerPort: 9100
---
apiVersion: v1
kind: Service
metadata:
  name: node-exporter
  namespace: gitlab-observability
spec:
  selector:
    app: node-exporter
  ports:
    - port: 9100
      targetPort: 9100
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># node-exporter-daemonset.yaml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">apps/v1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">DaemonSet
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">    matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">      app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">  template</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">    metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">      labels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">        app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">    spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">      containers</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="17"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="18"><span style="--shiki-default:#22863A">          image</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prom/node-exporter:latest
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">          ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="20"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">containerPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9100
</span></span><span class="line" line="21"><span style="--shiki-default:#6F42C1">---
</span></span><span class="line" line="22"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">v1
</span></span><span class="line" line="23"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Service
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="26"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="27"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="29"><span style="--shiki-default:#22863A">    app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">node-exporter
</span></span><span class="line" line="30"><span style="--shiki-default:#22863A">  ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="31"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9100
</span></span><span class="line" line="32"><span style="--shiki-default:#22863A">      targetPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9100
</span></span></code></pre><h3 id="_4-deploy-prometheus">4. Deploy Prometheus</h3><pre className="language-yaml shiki shiki-themes github-light" code="# prometheus-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: gitlab-observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
        - name: prometheus
          image: prom/prometheus:latest
          ports:
            - containerPort: 9090
          volumeMounts:
            - name: config
              mountPath: /etc/prometheus
      volumes:
        - name: config
          configMap:
            name: prometheus-config
---
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: gitlab-observability
spec:
  selector:
    app: prometheus
  ports:
    - port: 9090
      targetPort: 9090
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># prometheus-deployment.yaml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">apps/v1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Deployment
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  replicas</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">1
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">    matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">      app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">  template</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">    metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">      labels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">        app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">    spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="17"><span style="--shiki-default:#22863A">      containers</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">          image</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prom/prometheus:latest
</span></span><span class="line" line="20"><span style="--shiki-default:#22863A">          ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="21"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">containerPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9090
</span></span><span class="line" line="22"><span style="--shiki-default:#22863A">          volumeMounts</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="23"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">config
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">              mountPath</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/etc/prometheus
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">      volumes</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="26"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">config
</span></span><span class="line" line="27"><span style="--shiki-default:#22863A">          configMap</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">            name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus-config
</span></span><span class="line" line="29"><span style="--shiki-default:#6F42C1">---
</span></span><span class="line" line="30"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">v1
</span></span><span class="line" line="31"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Service
</span></span><span class="line" line="32"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="33"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="34"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="35"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="36"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="37"><span style="--shiki-default:#22863A">    app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="38"><span style="--shiki-default:#22863A">  ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="39"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9090
</span></span><span class="line" line="40"><span style="--shiki-default:#22863A">      targetPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9090
</span></span></code></pre><h3 id="_5-deploy-grafana">5. Deploy Grafana</h3><p>The Grafana deployment below starts with authentication disabled (<code className="">GF_AUTH_ANONYMOUS_ENABLED: true</code>) for initial setup convenience.</p><p><strong>This setting allows anyone with network access to view all dashboards without logging in.</strong> For production deployments, remove this variable or set it to false and configure a proper authentication provider (LDAP, SAML/SSO, or OAuth) to restrict access to authorized users.</p><pre className="language-yaml shiki shiki-themes github-light" code="# grafana-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: gitlab-observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
        - name: grafana
          image: grafana/grafana:10.0.0
          ports:
            - containerPort: 3000
          env:
            # REMOVE or set to &#39;false&#39; for production.
            # When &#39;true&#39;, any user with network access can
            # view dashboards without authentication.
            - name: GF_AUTH_ANONYMOUS_ENABLED
              value: &#39;true&#39;
          volumeMounts:
            - name: dashboards-provider
              mountPath: /etc/grafana/provisioning/dashboards
            - name: datasources
              mountPath: /etc/grafana/provisioning/datasources
            - name: dashboards
              mountPath: /var/lib/grafana/dashboards
      volumes:
        - name: dashboards-provider
          configMap:
            name: grafana-dashboards-provider
        - name: datasources
          configMap:
            name: grafana-datasources
        - name: dashboards
          configMap:
            name: grafana-dashboards
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: gitlab-observability
spec:
  selector:
    app: grafana
  ports:
    - port: 3000
      targetPort: 3000
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># grafana-deployment.yaml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">apps/v1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Deployment
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  replicas</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">1
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">    matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">      app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">  template</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">    metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">      labels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">        app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">    spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="17"><span style="--shiki-default:#22863A">      containers</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">          image</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana/grafana:10.0.0
</span></span><span class="line" line="20"><span style="--shiki-default:#22863A">          ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="21"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">containerPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">3000
</span></span><span class="line" line="22"><span style="--shiki-default:#22863A">          env</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="23"><span style="--shiki-default:#6A737D">            # REMOVE or set to &#39;false&#39; for production.
</span></span><span class="line" line="24"><span style="--shiki-default:#6A737D">            # When &#39;true&#39;, any user with network access can
</span></span><span class="line" line="25"><span style="--shiki-default:#6A737D">            # view dashboards without authentication.
</span></span><span class="line" line="26"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">GF_AUTH_ANONYMOUS_ENABLED
</span></span><span class="line" line="27"><span style="--shiki-default:#22863A">              value</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;true&#39;
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">          volumeMounts</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="29"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">dashboards-provider
</span></span><span class="line" line="30"><span style="--shiki-default:#22863A">              mountPath</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/etc/grafana/provisioning/dashboards
</span></span><span class="line" line="31"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">datasources
</span></span><span class="line" line="32"><span style="--shiki-default:#22863A">              mountPath</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/etc/grafana/provisioning/datasources
</span></span><span class="line" line="33"><span style="--shiki-default:#24292E">            - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">dashboards
</span></span><span class="line" line="34"><span style="--shiki-default:#22863A">              mountPath</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/var/lib/grafana/dashboards
</span></span><span class="line" line="35"><span style="--shiki-default:#22863A">      volumes</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="36"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">dashboards-provider
</span></span><span class="line" line="37"><span style="--shiki-default:#22863A">          configMap</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="38"><span style="--shiki-default:#22863A">            name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana-dashboards-provider
</span></span><span class="line" line="39"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">datasources
</span></span><span class="line" line="40"><span style="--shiki-default:#22863A">          configMap</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="41"><span style="--shiki-default:#22863A">            name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana-datasources
</span></span><span class="line" line="42"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">dashboards
</span></span><span class="line" line="43"><span style="--shiki-default:#22863A">          configMap</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="44"><span style="--shiki-default:#22863A">            name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana-dashboards
</span></span><span class="line" line="45"><span style="--shiki-default:#6F42C1">---
</span></span><span class="line" line="46"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">v1
</span></span><span class="line" line="47"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Service
</span></span><span class="line" line="48"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="49"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="50"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="51"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="52"><span style="--shiki-default:#22863A">  selector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="53"><span style="--shiki-default:#22863A">    app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="54"><span style="--shiki-default:#22863A">  ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="55"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">3000
</span></span><span class="line" line="56"><span style="--shiki-default:#22863A">      targetPort</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">3000
</span></span></code></pre><h3 id="_6-set-network-policy">6. Set network policy</h3><p>Restrict inter-pod traffic to only the required communication paths:</p><pre className="language-yaml shiki shiki-themes github-light" code="# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: observability-policy
  namespace: gitlab-observability
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    # Prometheus scrapes exporter and node-exporter
    - from:
        - podSelector:
            matchLabels:
              app: prometheus
      ports:
        - port: 8080
        - port: 9100
    # Grafana queries Prometheus
    - from:
        - podSelector:
            matchLabels:
              app: grafana
      ports:
        - port: 9090
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># network-policy.yaml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">networking.k8s.io/v1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">NetworkPolicy
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">metadata</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">observability-policy
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  namespace</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab-observability
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  podSelector</span><span style="--shiki-default:#24292E">: {}
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">  policyTypes</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">Ingress
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">  ingress</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#6A737D">    # Prometheus scrapes exporter and node-exporter
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">from</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">podSelector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">            matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">              app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="17"><span style="--shiki-default:#22863A">      ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">8080
</span></span><span class="line" line="19"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9100
</span></span><span class="line" line="20"><span style="--shiki-default:#6A737D">    # Grafana queries Prometheus
</span></span><span class="line" line="21"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">from</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="22"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">podSelector</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="23"><span style="--shiki-default:#22863A">            matchLabels</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">              app</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">grafana
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">      ports</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="26"><span style="--shiki-default:#24292E">        - </span><span style="--shiki-default:#22863A">port</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">9090
</span></span></code></pre><h3 id="_7-validate">7. Validate</h3><pre className="language-bash shiki shiki-themes github-light" code="kubectl get pods -n gitlab-observability
kubectl port-forward svc/grafana 3000:3000 -n gitlab-observability
curl http://localhost:3000/api/health
" language="bash" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> get</span><span style="--shiki-default:#032F62"> pods</span><span style="--shiki-default:#005CC5"> -n</span><span style="--shiki-default:#032F62"> gitlab-observability
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> port-forward</span><span style="--shiki-default:#032F62"> svc/grafana</span><span style="--shiki-default:#032F62"> 3000:3000</span><span style="--shiki-default:#005CC5"> -n</span><span style="--shiki-default:#032F62"> gitlab-observability
</span></span><span class="line" line="3"><span style="--shiki-default:#6F42C1">curl</span><span style="--shiki-default:#032F62"> http://localhost:3000/api/health
</span></span></code></pre><h2 id="configuration-reference">Configuration reference</h2><h3 id="exporter-configuration">Exporter configuration</h3><pre className="language-yaml shiki shiki-themes github-light" code="# gitlab-ci-pipelines-exporter.yml (ConfigMap: gcpe-config)
log:
  level: info
gitlab:
  url: https://gitlab.your-domain.com
  maximum_requests_per_second: 10
project_defaults:
  pull:
    pipeline:
      jobs:
        enabled: true
wildcards:
  - owner:
      name: your-group-name
      kind: group
    archived: false
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># gitlab-ci-pipelines-exporter.yml (ConfigMap: gcpe-config)
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">log</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">  level</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">info
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">gitlab</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">  url</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">https://gitlab.your-domain.com
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  maximum_requests_per_second</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">10
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">project_defaults</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  pull</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">    pipeline</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">      jobs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">        enabled</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">true
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">wildcards</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">owner</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">      name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">your-group-name
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">      kind</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">group
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">    archived</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false
</span></span></code></pre><h3 id="prometheus-configuration">Prometheus configuration</h3><pre className="language-yaml shiki shiki-themes github-light" code="# prometheus.yml (ConfigMap: prometheus-config)
global:
  scrape_interval: 15s
scrape_configs:
  - job_name: &#39;gitlab-ci-pipelines-exporter&#39;
    static_configs:
      - targets: [&#39;gitlab-ci-pipelines-exporter:8080&#39;]
  - job_name: &#39;node-exporter&#39;
    static_configs:
      - targets: [&#39;node-exporter:9100&#39;]
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># prometheus.yml (ConfigMap: prometheus-config)
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">global</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">  scrape_interval</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">15s
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">scrape_configs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">job_name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;gitlab-ci-pipelines-exporter&#39;
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">    static_configs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">targets</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">&#39;gitlab-ci-pipelines-exporter:8080&#39;</span><span style="--shiki-default:#24292E">]
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">job_name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;node-exporter&#39;
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">    static_configs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">targets</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">&#39;node-exporter:9100&#39;</span><span style="--shiki-default:#24292E">]
</span></span></code></pre><h3 id="grafana-data-sources">Grafana data sources</h3><pre className="language-yaml shiki shiki-themes github-light" code="# datasources.yml (ConfigMap: grafana-datasources)
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
# dashboards.yml (ConfigMap: grafana-dashboards-provider)
apiVersion: 1
providers:
  - name: &#39;default&#39;
    folder: &#39;GitLab CI/CD&#39;
    type: file
    options:
      path: /var/lib/grafana/dashboards
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># datasources.yml (ConfigMap: grafana-datasources)
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">1
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">datasources</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">Prometheus
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">    type</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prometheus
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">    access</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">proxy
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">    url</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">http://prometheus:9090
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">    isDefault</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">true
</span></span><span class="line" line="9"><span style="--shiki-default:#6A737D"># dashboards.yml (ConfigMap: grafana-dashboards-provider)
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">apiVersion</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">1
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">providers</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;default&#39;
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">    folder</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;GitLab CI/CD&#39;
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">    type</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">file
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">    options</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">      path</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">/var/lib/grafana/dashboards
</span></span></code></pre><h2 id="key-metrics">Key metrics</h2><h3 id="pipeline-exporter-metrics">Pipeline Exporter metrics</h3><table><thead><tr><th align="left">Metric</th><th align="left">Description</th></tr></thead><tbody><tr><td align="left"><code className="">gitlab_ci_pipeline_duration_seconds</code></td><td align="left">Pipeline execution time</td></tr><tr><td align="left"><code className="">gitlab_ci_pipeline_status</code></td><td align="left">Pipeline success/failure by project</td></tr><tr><td align="left"><code className="">gitlab_ci_pipeline_job_duration_seconds</code></td><td align="left">Individual job execution time</td></tr><tr><td align="left"><code className="">gitlab_ci_pipeline_job_status</code></td><td align="left">Job success/failure status</td></tr><tr><td align="left"><code className="">gitlab_ci_pipeline_job_artifact_size_bytes</code></td><td align="left">Artifact storage consumption</td></tr><tr><td align="left"><code className="">gitlab_ci_pipeline_coverage</code></td><td align="left">Code coverage percentage</td></tr><tr><td align="left"><code className="">gitlab_ci_environment_deployment_count</code></td><td align="left">Deployment frequency</td></tr><tr><td align="left"><code className="">gitlab_ci_environment_deployment_duration_seconds</code></td><td align="left">Deployment execution time</td></tr><tr><td align="left"><code className="">gitlab_ci_environment_behind_commits_count</code></td><td align="left">Environment drift from main</td></tr></tbody></table><h3 id="node-exporter-metrics">Node Exporter metrics</h3><table><thead><tr><th align="left">Metric</th><th align="left">Description</th></tr></thead><tbody><tr><td align="left"><code className="">node_cpu_seconds_total</code></td><td align="left">CPU utilization</td></tr><tr><td align="left"><code className="">node_memory_MemAvailable_bytes</code></td><td align="left">Available memory</td></tr><tr><td align="left"><code className="">node_filesystem_avail_bytes</code></td><td align="left">Disk space available</td></tr><tr><td align="left"><code className="">node_load1</code></td><td align="left">1-minute load average</td></tr></tbody></table><h2 id="troubleshooting">Troubleshooting</h2><h3 id="air-gapped-grafana-plugin-installation">Air-gapped Grafana plugin installation</h3><p>For offline environments, install plugins manually. Example for Kubernetes:</p><pre className="language-bash shiki shiki-themes github-light" code="# Copy plugin zip into the Grafana pod
kubectl cp grafana-polystat-panel-2.1.16.zip \
  gitlab-observability/grafana-&lt;pod-id&gt;:/tmp/
# Extract plugin
kubectl exec -it -n gitlab-observability deploy/grafana -- \
  sh -c &quot;unzip /tmp/grafana-polystat-panel-2.1.16.zip -d /var/lib/grafana/plugins/&quot;
# Restart Grafana pod
kubectl rollout restart deployment/grafana -n gitlab-observability
# Verify installation
kubectl exec -it -n gitlab-observability deploy/grafana -- \
  ls -al /var/lib/grafana/plugins/
" language="bash" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># Copy plugin zip into the Grafana pod
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> cp</span><span style="--shiki-default:#032F62"> grafana-polystat-panel-2.1.16.zip</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="3"><span style="--shiki-default:#032F62">  gitlab-observability/grafana-</span><span style="--shiki-default:#D73A49">&lt;</span><span style="--shiki-default:#032F62">pod-i</span><span style="--shiki-default:#24292E">d</span><span style="--shiki-default:#D73A49">&gt;</span><span style="--shiki-default:#032F62">:/tmp/
</span></span><span class="line" line="4"><span style="--shiki-default:#6A737D"># Extract plugin
</span></span><span class="line" line="5"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> exec</span><span style="--shiki-default:#005CC5"> -it</span><span style="--shiki-default:#005CC5"> -n</span><span style="--shiki-default:#032F62"> gitlab-observability</span><span style="--shiki-default:#032F62"> deploy/grafana</span><span style="--shiki-default:#005CC5"> --</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="6"><span style="--shiki-default:#032F62">  sh</span><span style="--shiki-default:#005CC5"> -c</span><span style="--shiki-default:#032F62"> &quot;unzip /tmp/grafana-polystat-panel-2.1.16.zip -d /var/lib/grafana/plugins/&quot;
</span></span><span class="line" line="7"><span style="--shiki-default:#6A737D"># Restart Grafana pod
</span></span><span class="line" line="8"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> rollout</span><span style="--shiki-default:#032F62"> restart</span><span style="--shiki-default:#032F62"> deployment/grafana</span><span style="--shiki-default:#005CC5"> -n</span><span style="--shiki-default:#032F62"> gitlab-observability
</span></span><span class="line" line="9"><span style="--shiki-default:#6A737D"># Verify installation
</span></span><span class="line" line="10"><span style="--shiki-default:#6F42C1">kubectl</span><span style="--shiki-default:#032F62"> exec</span><span style="--shiki-default:#005CC5"> -it</span><span style="--shiki-default:#005CC5"> -n</span><span style="--shiki-default:#032F62"> gitlab-observability</span><span style="--shiki-default:#032F62"> deploy/grafana</span><span style="--shiki-default:#005CC5"> --</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="11"><span style="--shiki-default:#032F62">  ls</span><span style="--shiki-default:#005CC5"> -al</span><span style="--shiki-default:#032F62"> /var/lib/grafana/plugins/
</span></span></code></pre><h2 id="enterprise-considerations">Enterprise considerations</h2><p>For regulated industries, ensure:</p><ul><li><strong>Token security:</strong> Store GitLab Personal Access Tokens in a dedicated secrets manager rather than hardcoded in ConfigMaps. Enforce token rotation policies and limit scope to <strong>read_api</strong> only.</li><li><strong>Network segmentation:</strong> Deploy behind a reverse proxy with TLS termination. In Kubernetes, use an Ingress controller with automated certificate provisioning.</li><li><strong>Authentication:</strong> Configure Grafana with your organization&#39;s identity provider (SAML, LDAP, or OAuth/OIDC) to enforce role-based access control on dashboards.</li></ul><h2 id="why-gitlab">Why GitLab?</h2><p>GitLab&#39;s API-first design enables custom observability solutions that complement native capabilities like Value Stream Analytics and DORA metrics. The open architecture allows organizations to integrate proven open-source tooling — like the gitlab-ci-pipelines-exporter — directly with their existing enterprise infrastructure, without disrupting established workflows.</p><p>As your observability maturity grows, GitLab&#39;s built-in Observability capabilities provide a natural next step — offering deeper, integrated visibility without additional tooling. Learn more about what&#39;s available natively in the platform for <a href="https://docs.gitlab.com/operations/observability/observability/" rel="">GitLab Observability</a>.</p><style>html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}</style>]]></content>
        <author>
            <name>Paul Meresanu</name>
            <uri>https://about.gitlab.com/blog/authors/paul-meresanu/</uri>
        </author>
        <published>2026-04-28T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab and Anthropic: Governed AI for enterprise development]]></title>
        <id>https://about.gitlab.com/blog/gitlab-and-anthropic-governed-ai-for-enterprise-development/</id>
        <link href="https://about.gitlab.com/blog/gitlab-and-anthropic-governed-ai-for-enterprise-development/"/>
        <updated>2026-04-28T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>For enterprise and public sector leaders, the tension is familiar: Software teams need to move faster with AI, while security, compliance, and regulatory expectations only get more stringent. GitLab deepens its Anthropic Claude integration so organizations get access to newly released Claude models inside GitLab’s intelligent orchestration platform where governance, compliance, and auditability already run.</p><p>Claude powers capabilities across GitLab Duo Agent Platform as the default model out of the box, across a variety of use cases from code generation and review to agentic chat and vulnerability resolution. If you&#39;ve used GitLab Duo, you&#39;ve already experienced how Duo agents automate workflows across the entire software development lifecycle (SDLC).</p><p>This accelerates the integration of Claude’s capabilities into GitLab, broadens how enterprises can deploy them, and reinforces what makes GitLab fundamentally different as a platform for software development and engineering: governance, compliance, and auditability built into every AI interaction.</p><blockquote><p>&quot;GitLab Duo has accelerated how our teams plan, build, and ship software. The combination of Anthropic&#39;s Claude and GitLab&#39;s platform means we&#39;re getting more capable AI without changing how we work or how it is governed.&quot;</p><p>– Mans Booijink, Operations Manager, Cube</p></blockquote><h2 id="the-real-differentiator-governed-ai">The real differentiator: Governed AI</h2><p>With GitLab, governance controls and auditing are built into the SDLC. When Claude suggests a code change through the GitLab Duo Agent Platform, that suggestion flows through the same merge request process, the same approval rules, the same security scanning, and the same audit trail as every other change. AI doesn&#39;t get a shortcut around your controls. It operates within them.</p><p>As GitLab moves deeper into agentic software development, where AI autonomously handles well-defined tasks, the governance layer becomes more important. An AI agent that can open a merge request, help resolve a vulnerability, or refactor a service needs to be auditable, attributable, and subject to the same policy enforcement as a human developer. That requirement is an architectural decision GitLab made from the start, and one that grows more consequential as AI agents take on broader responsibilities.</p><h2 id="enterprise-deployment-flexibility">Enterprise deployment flexibility</h2><p>This also expands how organizations access the latest Claude models through GitLab. Claude is available within GitLab through Google Cloud&#39;s Vertex AI and Amazon Bedrock, which means enterprises can route AI workloads through the hyperscaler commitments and cloud governance frameworks they already have in place. No separate vendor contract. No new data residency questions. Your existing Google Cloud or AWS relationship is the on-ramp.</p><p>GitLab is now also available in the <a href="https://claude.com/platform/marketplace" rel="">Claude Marketplace</a>, allowing customers to purchase GitLab Credits and apply them toward existing Anthropic spending commitments – consolidating AI spend and simplifying how teams discover and procure GitLab alongside their Anthropic investments.</p><h2 id="advancing-an-agentic-future">Advancing an agentic future</h2><p>GitLab&#39;s vision for agentic software development, where AI handles defined tasks autonomously across planning, coding, testing, securing, and deploying, requires models with strong reasoning, reliability, and safety characteristics. It also requires a platform where those autonomous actions are fully governed.</p><p>Agentic workflows demand models with strong reasoning, reliability, and safety characteristics, criteria that guide how GitLab selects and integrates AI model partners. And GitLab&#39;s governance framework helps ensure that as AI agents assume more advanced development work, enterprises maintain full visibility and control over what those agents do, when they do it, and how changes are tracked.</p><h2 id="what-this-means-for-gitlab-customers">What this means for GitLab customers</h2><p>If you&#39;re already using GitLab Duo Agent Platform, you&#39;ll get access to Claude models and deeper AI assistance across your software development lifecycle, all within the governance framework you already rely on.</p><p>If you&#39;re evaluating AI-powered software development platforms, you shouldn&#39;t have to choose between advanced AI capabilities and enterprise control. This strategic integration is built to deliver both.</p><blockquote><p>Want to learn more about GitLab Duo Agent Platform? <a href="https://about.gitlab.com/gitlab-duo-agent-platform/" rel="">Get a demo or start a free trial today</a>.</p></blockquote>]]></content>
        <author>
            <name>Stuart Moncada</name>
            <uri>https://about.gitlab.com/blog/authors/stuart-moncada/</uri>
        </author>
        <published>2026-04-28T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Give your AI agent direct, structured GitLab access with glab CLI]]></title>
        <id>https://about.gitlab.com/blog/give-your-ai-agent-direct-structured-gitlab-access-with-glab-cli/</id>
        <link href="https://about.gitlab.com/blog/give-your-ai-agent-direct-structured-gitlab-access-with-glab-cli/"/>
        <updated>2026-04-27T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>When teams use GitLab Duo, Claude, Cursor, and other AI assistants, more of the development workflow runs through an AI agent acting on your behalf — reading issues, reviewing merge requests, running pipelines, and helping you ship faster. Most developers are already using the GitLab CLI (<code className="">glab</code>) from the terminal to interact with GitLab. Combining the two is a natural next step.</p><p>The problem is that without the right tools, AI agents are essentially guessing when it comes to your GitLab projects. They might hallucinate the details of an issue they&#39;ve never seen, summarize a merge request based on stale training data rather than its actual state, or require you to manually copy context from a browser tab and paste it into a chat window just to get started. Every one of those workarounds is friction: it slows you down, introduces the possibility of error, and puts a hard ceiling on what your agent can actually do on your behalf. <code className="">glab</code> changes that by giving agents a direct, reliable interface to your projects.</p><p>With <code className="">glab</code>, your agent fetches what it needs directly from GitLab, acts on it, and reports back — so you spend less time relaying information and more time on the work that matters.</p><p>In this tutorial, you&#39;ll learn how to use <code className="">glab</code> to give AI agents structured, reliable access to your GitLab projects. You&#39;ll also discover how that unlocks a faster, more capable development workflow.</p><h2 id="how-to-connect-your-ai-agent-to-gitlab-through-mcp">How to connect your AI agent to GitLab through MCP</h2><p>The most direct way to supercharge your AI workflow is to give your AI agent native access to <code className="">glab</code> through Model Context Protocol (<a href="https://about.gitlab.com/topics/ai/model-context-protocol/" rel="">MCP</a>).</p><p>MCP is an open standard that lets AI tools discover and use external capabilities at runtime. Once connected, your AI assistant can read issues, comment on merge requests, check pipeline status, and write back to GitLab, all without copying anything from the UI or writing a single API call yourself.</p><p>To get started, run:</p><pre className="language-shell shiki shiki-themes github-light" code="# Start the glab MCP server
glab mcp serve
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># Start the glab MCP server
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mcp</span><span style="--shiki-default:#032F62"> serve
</span></span></code></pre><p>Once your MCP client is configured, your AI can answer questions like <em>&quot;What&#39;s the status of my open MRs?&quot;</em> or <em>&quot;Are there any failing pipelines on main?&quot;</em> by querying GitLab directly, not scraping the web UI, not relying on stale training data. See the <a href="https://docs.gitlab.com/cli/" rel="">full setup docs</a> for configuration steps for Claude Code, Cursor, and other editors.</p><p>One detail worth knowing: <code className="">glab</code> automatically adds <code className="">--output json</code> when invoked through MCP, for any command that supports it. Your agent gets clean, structured data without you needing to think about output formats. And because <code className="">glab</code> uses the official MCP SDK, it stays compatible as the
protocol evolves.</p><p>We&#39;ve also been deliberate about <em>which</em> commands are exposed through MCP. Commands that require interactive terminal input are intentionally
excluded, so your agent never gets stuck waiting for input that will never come. What&#39;s exposed is what actually works reliably in an agent context.</p><h2 id="let-your-ai-participate-in-code-review">Let your AI participate in code review</h2><p>Most developers have a backlog of MRs waiting for review. It&#39;s one of the most time-consuming parts of the job and one of the best places to put
AI to work. With <code className="">glab</code>, your agent doesn&#39;t just observe your review queue, it can work through it with you.</p><h3 id="see-exactly-what-still-needs-addressing">See exactly what still needs addressing</h3><p>Start with this:</p><pre className="language-shell shiki shiki-themes github-light" code="glab mr view 2677 --comments --unresolved --output json
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mr</span><span style="--shiki-default:#032F62"> view</span><span style="--shiki-default:#005CC5"> 2677</span><span style="--shiki-default:#005CC5"> --comments</span><span style="--shiki-default:#005CC5"> --unresolved</span><span style="--shiki-default:#005CC5"> --output</span><span style="--shiki-default:#032F62"> json
</span></span></code></pre><p>This input returns the full MR: metadata, description, and every
unresolved discussion, as a single structured JSON payload. Hand that to
your AI and it has everything it needs: which threads are open, what the
reviewer asked for, and in what context. No tab-switching, no copy-pasting
individual comments.</p><pre className="language-json shiki shiki-themes github-light" code="{
  &quot;id&quot;: 2677,
  &quot;title&quot;: &quot;feat: add OAuth2 support&quot;,
  &quot;state&quot;: &quot;opened&quot;,
  &quot;author&quot;: { &quot;username&quot;: &quot;jdwick&quot; },
  &quot;labels&quot;: [&quot;backend&quot;, &quot;needs-review&quot;],
  &quot;blocking_discussions_resolved&quot;: false,
  &quot;discussions&quot;: [
    {
      &quot;id&quot;: &quot;3107030349&quot;,
      &quot;resolved&quot;: false,
      &quot;notes&quot;: [
        {
          &quot;author&quot;: { &quot;username&quot;: &quot;dmurphy&quot; },
          &quot;body&quot;: &quot;This error handling will swallow panics — consider wrapping with recover()&quot;,
          &quot;created_at&quot;: &quot;2026-03-14T09:23:11.000Z&quot;
        }
      ]
    },
    {
      &quot;id&quot;: &quot;3107030412&quot;,
      &quot;resolved&quot;: false,
      &quot;notes&quot;: [
        {
          &quot;author&quot;: { &quot;username&quot;: &quot;sreeves&quot; },
          &quot;body&quot;: &quot;Token refresh logic needs a test for the expired token case&quot;,
          &quot;created_at&quot;: &quot;2026-03-14T10:05:44.000Z&quot;
        }
      ]
    }
  ]
}
" language="json" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#24292E">{
</span></span><span class="line" line="2"><span style="--shiki-default:#005CC5">  &quot;id&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">2677</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="3"><span style="--shiki-default:#005CC5">  &quot;title&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;feat: add OAuth2 support&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="4"><span style="--shiki-default:#005CC5">  &quot;state&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;opened&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="5"><span style="--shiki-default:#005CC5">  &quot;author&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;jdwick&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="6"><span style="--shiki-default:#005CC5">  &quot;labels&quot;</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">&quot;backend&quot;</span><span style="--shiki-default:#24292E">, </span><span style="--shiki-default:#032F62">&quot;needs-review&quot;</span><span style="--shiki-default:#24292E">],
</span></span><span class="line" line="7"><span style="--shiki-default:#005CC5">  &quot;blocking_discussions_resolved&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="8"><span style="--shiki-default:#005CC5">  &quot;discussions&quot;</span><span style="--shiki-default:#24292E">: [
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">    {
</span></span><span class="line" line="10"><span style="--shiki-default:#005CC5">      &quot;id&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;3107030349&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="11"><span style="--shiki-default:#005CC5">      &quot;resolved&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="12"><span style="--shiki-default:#005CC5">      &quot;notes&quot;</span><span style="--shiki-default:#24292E">: [
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">        {
</span></span><span class="line" line="14"><span style="--shiki-default:#005CC5">          &quot;author&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;dmurphy&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="15"><span style="--shiki-default:#005CC5">          &quot;body&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;This error handling will swallow panics — consider wrapping with recover()&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="16"><span style="--shiki-default:#005CC5">          &quot;created_at&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;2026-03-14T09:23:11.000Z&quot;
</span></span><span class="line" line="17"><span style="--shiki-default:#24292E">        }
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">      ]
</span></span><span class="line" line="19"><span style="--shiki-default:#24292E">    },
</span></span><span class="line" line="20"><span style="--shiki-default:#24292E">    {
</span></span><span class="line" line="21"><span style="--shiki-default:#005CC5">      &quot;id&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;3107030412&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="22"><span style="--shiki-default:#005CC5">      &quot;resolved&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="23"><span style="--shiki-default:#005CC5">      &quot;notes&quot;</span><span style="--shiki-default:#24292E">: [
</span></span><span class="line" line="24"><span style="--shiki-default:#24292E">        {
</span></span><span class="line" line="25"><span style="--shiki-default:#005CC5">          &quot;author&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;sreeves&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="26"><span style="--shiki-default:#005CC5">          &quot;body&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;Token refresh logic needs a test for the expired token case&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="27"><span style="--shiki-default:#005CC5">          &quot;created_at&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;2026-03-14T10:05:44.000Z&quot;
</span></span><span class="line" line="28"><span style="--shiki-default:#24292E">        }
</span></span><span class="line" line="29"><span style="--shiki-default:#24292E">      ]
</span></span><span class="line" line="30"><span style="--shiki-default:#24292E">    }
</span></span><span class="line" line="31"><span style="--shiki-default:#24292E">  ]
</span></span><span class="line" line="32"><span style="--shiki-default:#24292E">}
</span></span></code></pre><p>Instead of reading through every thread yourself, you ask your agent  <em>&quot;what do I still need to fix in MR 2677?&quot;</em> and get back a prioritized summary with suggested changes. This all happens from a single command.</p><h3 id="close-the-loop-programmatically">Close the loop programmatically</h3><p>Once your AI has helped you address the feedback, it can resolve
discussions:</p><pre className="language-shell shiki shiki-themes github-light" code="# List all discussions — structured, ready for the agent to process
glab mr note list 456 --output json

# Resolve a discussion once the feedback is addressed
glab mr note resolve 456 3107030349

# Reopen if something needs another look
glab mr note reopen 456 3107030349
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># List all discussions — structured, ready for the agent to process
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mr</span><span style="--shiki-default:#032F62"> note</span><span style="--shiki-default:#032F62"> list</span><span style="--shiki-default:#005CC5"> 456</span><span style="--shiki-default:#005CC5"> --output</span><span style="--shiki-default:#032F62"> json
</span></span><span class="line" line="3"><span emptyLinePlaceholder>
</span></span><span class="line" line="4"><span style="--shiki-default:#6A737D"># Resolve a discussion once the feedback is addressed
</span></span><span class="line" line="5"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mr</span><span style="--shiki-default:#032F62"> note</span><span style="--shiki-default:#032F62"> resolve</span><span style="--shiki-default:#005CC5"> 456</span><span style="--shiki-default:#005CC5"> 3107030349
</span></span><span class="line" line="6"><span emptyLinePlaceholder>
</span></span><span class="line" line="7"><span style="--shiki-default:#6A737D"># Reopen if something needs another look
</span></span><span class="line" line="8"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mr</span><span style="--shiki-default:#032F62"> note</span><span style="--shiki-default:#032F62"> reopen</span><span style="--shiki-default:#005CC5"> 456</span><span style="--shiki-default:#005CC5"> 3107030349
</span></span></code></pre><pre className="language-json shiki shiki-themes github-light" code="[
  {
    &quot;id&quot;: 3107030349,
    &quot;body&quot;: &quot;This error handling will swallow panics — consider wrapping with recover()&quot;,
    &quot;author&quot;: { &quot;username&quot;: &quot;dmurphy&quot; },
    &quot;resolved&quot;: false,
    &quot;resolvable&quot;: true
  },
  {
    &quot;id&quot;: 3107030412,
    &quot;body&quot;: &quot;Token refresh logic needs a test for the expired token case&quot;,
    &quot;author&quot;: { &quot;username&quot;: &quot;sreeves&quot; },
    &quot;resolved&quot;: false,
    &quot;resolvable&quot;: true
  }
]
" language="json" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#24292E">[
</span></span><span class="line" line="2"><span style="--shiki-default:#24292E">  {
</span></span><span class="line" line="3"><span style="--shiki-default:#005CC5">    &quot;id&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">3107030349</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="4"><span style="--shiki-default:#005CC5">    &quot;body&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;This error handling will swallow panics — consider wrapping with recover()&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="5"><span style="--shiki-default:#005CC5">    &quot;author&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;dmurphy&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="6"><span style="--shiki-default:#005CC5">    &quot;resolved&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="7"><span style="--shiki-default:#005CC5">    &quot;resolvable&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">true
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">  },
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">  {
</span></span><span class="line" line="10"><span style="--shiki-default:#005CC5">    &quot;id&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">3107030412</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="11"><span style="--shiki-default:#005CC5">    &quot;body&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;Token refresh logic needs a test for the expired token case&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="12"><span style="--shiki-default:#005CC5">    &quot;author&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;sreeves&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="13"><span style="--shiki-default:#005CC5">    &quot;resolved&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">false</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="14"><span style="--shiki-default:#005CC5">    &quot;resolvable&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">true
</span></span><span class="line" line="15"><span style="--shiki-default:#24292E">  }
</span></span><span class="line" line="16"><span style="--shiki-default:#24292E">]
</span></span></code></pre><p>Note IDs are visible directly in the GitLab UI and API, no extra lookup needed. Your agent can work through the full list, verify each fix, and
resolve as it goes.</p><h2 id="talk-to-your-ai-about-your-code-more-effectively">Talk to your AI about your code more effectively</h2><p>Even if you&#39;re not running an MCP server, there&#39;s a simpler shift that makes a huge difference: using <code className="">glab</code> to feed your AI better information.</p><p>Think about the last time you asked an AI assistant to help triage issues or debug a failing pipeline. You probably copied some text from the GitLab UI and pasted it into the chat. Here&#39;s what your agent is actually
working with when you do that:</p><pre className="language-text" code="open issues: 12 • milestone: 17.10 • label: bug, needs-triage ...
" language="text" meta=""><code>open issues: 12 • milestone: 17.10 • label: bug, needs-triage ...
</code></pre><p>Compare that to what it gets with <code className="">glab</code>:</p><pre className="language-json shiki shiki-themes github-light" code="[
  {
    &quot;iid&quot;: 902,
    &quot;title&quot;: &quot;Pipeline fails on merge to main&quot;,
    &quot;labels&quot;: [&quot;bug&quot;, &quot;needs-triage&quot;],
    &quot;milestone&quot;: { &quot;title&quot;: &quot;17.10&quot; },
    &quot;assignees&quot;: []
  },
  ...
]
" language="json" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#24292E">[
</span></span><span class="line" line="2"><span style="--shiki-default:#24292E">  {
</span></span><span class="line" line="3"><span style="--shiki-default:#005CC5">    &quot;iid&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#005CC5">902</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="4"><span style="--shiki-default:#005CC5">    &quot;title&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;Pipeline fails on merge to main&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="5"><span style="--shiki-default:#005CC5">    &quot;labels&quot;</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">&quot;bug&quot;</span><span style="--shiki-default:#24292E">, </span><span style="--shiki-default:#032F62">&quot;needs-triage&quot;</span><span style="--shiki-default:#24292E">],
</span></span><span class="line" line="6"><span style="--shiki-default:#005CC5">    &quot;milestone&quot;</span><span style="--shiki-default:#24292E">: { </span><span style="--shiki-default:#005CC5">&quot;title&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;17.10&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="7"><span style="--shiki-default:#005CC5">    &quot;assignees&quot;</span><span style="--shiki-default:#24292E">: []
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">  },
</span></span><span class="line" line="9"><span style="--shiki-default:#B31D28;--shiki-default-font-style:italic">  ...
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">]
</span></span></code></pre><p>Structured, typed, complete; no ambiguity, no parsing guesswork. That&#39;s the difference between an agent that can act and one that has to ask
follow-up questions.</p><p>If you&#39;re using the MCP server, you get this automatically: <code className="">glab</code> adds <code className="">--output json</code> for any command that supports it. If you&#39;re working directly
from the terminal, just add the flag yourself:</p><pre className="language-shell shiki shiki-themes github-light" code="# Pull open issues for triage
glab issue list --label &quot;needs-triage&quot; --output json

# Check pipeline status
glab ci status --output json

# Get full MR details
glab mr view 456 --output json
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># Pull open issues for triage
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> issue</span><span style="--shiki-default:#032F62"> list</span><span style="--shiki-default:#005CC5"> --label</span><span style="--shiki-default:#032F62"> &quot;needs-triage&quot;</span><span style="--shiki-default:#005CC5"> --output</span><span style="--shiki-default:#032F62"> json
</span></span><span class="line" line="3"><span emptyLinePlaceholder>
</span></span><span class="line" line="4"><span style="--shiki-default:#6A737D"># Check pipeline status
</span></span><span class="line" line="5"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> ci</span><span style="--shiki-default:#032F62"> status</span><span style="--shiki-default:#005CC5"> --output</span><span style="--shiki-default:#032F62"> json
</span></span><span class="line" line="6"><span emptyLinePlaceholder>
</span></span><span class="line" line="7"><span style="--shiki-default:#6A737D"># Get full MR details
</span></span><span class="line" line="8"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> mr</span><span style="--shiki-default:#032F62"> view</span><span style="--shiki-default:#005CC5"> 456</span><span style="--shiki-default:#005CC5"> --output</span><span style="--shiki-default:#032F62"> json
</span></span></code></pre><p>We&#39;ve significantly expanded JSON output support in recent releases. It now covers CI status, milestones, labels, releases, schedules, cluster agents, work items, MR approvers, repo contributors, and more. If <code className="">glab</code> can
retrieve it, your AI can consume it cleanly.</p><h3 id="a-real-workflow">A real workflow</h3><pre className="language-shell shiki shiki-themes github-light" code="$ glab issue list --label &quot;needs-triage&quot; --milestone &quot;17.10&quot;
--output json
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">$</span><span style="--shiki-default:#032F62"> glab</span><span style="--shiki-default:#032F62"> issue</span><span style="--shiki-default:#032F62"> list</span><span style="--shiki-default:#005CC5"> --label</span><span style="--shiki-default:#032F62"> &quot;needs-triage&quot;</span><span style="--shiki-default:#005CC5"> --milestone</span><span style="--shiki-default:#032F62"> &quot;17.10&quot;
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">--output</span><span style="--shiki-default:#032F62"> json
</span></span></code></pre><pre className="language-text" code="Agent: I found 2 unassigned bugs in the 17.10 milestone that need triage:
1. #902 — Pipeline fails on merge to main (opened 5 days ago)
2. #903 — Auth token not refreshing on expiry (opened 4 days ago)
Both are unassigned. Want me to draft triage notes and suggest assignees based on recent commit history?
" language="text" meta=""><code>Agent: I found 2 unassigned bugs in the 17.10 milestone that need triage:
1. #902 — Pipeline fails on merge to main (opened 5 days ago)
2. #903 — Auth token not refreshing on expiry (opened 4 days ago)
Both are unassigned. Want me to draft triage notes and suggest assignees based on recent commit history?
</code></pre><h2 id="your-agent-is-never-limited-to-built-in-commands">Your agent is never limited to built-in commands</h2><p><code className="">glab</code>&#39;s first-class commands cover the most common workflows, but your agent is never limited to them. Through <code className="">glab api</code>, it has authenticated access to the full GitLab REST and GraphQL API surface, using the same session, with no extra credentials or configuration required.</p><p>This is a meaningful differentiator. Most CLI tools stop at what their commands expose. With <code className="">glab</code>, if GitLab&#39;s API supports it, your agent can do it. It&#39;s always working from a trusted, authenticated context.</p><p>A practical example: fetching just the list of changed files in an MR before deciding which diffs to pull in full:</p><pre className="language-shell shiki shiki-themes github-light" code="# Get changed file paths — lightweight, no diff content yet
glab api &quot;/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/diffs?per_page=100&quot; \
| jq &#39;.[].new_path&#39;

# Then fetch only the specific file your agent needs
glab api &quot;/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/diffs?per_page=100&quot; \
| jq &#39;.[] | select(.new_path == &quot;path/to/file.go&quot;)&#39;
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># Get changed file paths — lightweight, no diff content yet
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> api</span><span style="--shiki-default:#032F62"> &quot;/projects/</span><span style="--shiki-default:#24292E">$CI_PROJECT_ID</span><span style="--shiki-default:#032F62">/merge_requests/</span><span style="--shiki-default:#24292E">$CI_MERGE_REQUEST_IID</span><span style="--shiki-default:#032F62">/diffs?per_page=100&quot;</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="3"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> jq</span><span style="--shiki-default:#032F62"> &#39;.[].new_path&#39;
</span></span><span class="line" line="4"><span emptyLinePlaceholder>
</span></span><span class="line" line="5"><span style="--shiki-default:#6A737D"># Then fetch only the specific file your agent needs
</span></span><span class="line" line="6"><span style="--shiki-default:#6F42C1">glab</span><span style="--shiki-default:#032F62"> api</span><span style="--shiki-default:#032F62"> &quot;/projects/</span><span style="--shiki-default:#24292E">$CI_PROJECT_ID</span><span style="--shiki-default:#032F62">/merge_requests/</span><span style="--shiki-default:#24292E">$CI_MERGE_REQUEST_IID</span><span style="--shiki-default:#032F62">/diffs?per_page=100&quot;</span><span style="--shiki-default:#005CC5"> \
</span></span><span class="line" line="7"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> jq</span><span style="--shiki-default:#032F62"> &#39;.[] | select(.new_path == &quot;path/to/file.go&quot;)&#39;
</span></span></code></pre><pre className="language-text" code="&quot;internal/auth/token.go&quot;
&quot;internal/auth/token_test.go&quot;
&quot;internal/oauth/refresh.go&quot;
" language="text" meta=""><code>&quot;internal/auth/token.go&quot;
&quot;internal/auth/token_test.go&quot;
&quot;internal/oauth/refresh.go&quot;
</code></pre><p>For anything the REST API doesn&#39;t cover (epics, certain work item queries, complex cross-project data),  <code className="">glab api graphql</code> gives you the full
GraphQL interface:</p><pre className="language-shell shiki shiki-themes github-light" code="  glab api graphql -f query=&#39;
{
  project(fullPath: &quot;gitlab-org/gitlab&quot;) {
    mergeRequest(iid: &quot;12345&quot;) {
      title
      reviewers { nodes { username } }
    }
  }
}&#39;
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">  glab</span><span style="--shiki-default:#032F62"> api</span><span style="--shiki-default:#032F62"> graphql</span><span style="--shiki-default:#005CC5"> -f</span><span style="--shiki-default:#032F62"> query=&#39;
</span></span><span class="line" line="2"><span style="--shiki-default:#032F62">{
</span></span><span class="line" line="3"><span style="--shiki-default:#032F62">  project(fullPath: &quot;gitlab-org/gitlab&quot;) {
</span></span><span class="line" line="4"><span style="--shiki-default:#032F62">    mergeRequest(iid: &quot;12345&quot;) {
</span></span><span class="line" line="5"><span style="--shiki-default:#032F62">      title
</span></span><span class="line" line="6"><span style="--shiki-default:#032F62">      reviewers { nodes { username } }
</span></span><span class="line" line="7"><span style="--shiki-default:#032F62">    }
</span></span><span class="line" line="8"><span style="--shiki-default:#032F62">  }
</span></span><span class="line" line="9"><span style="--shiki-default:#032F62">}&#39;
</span></span></code></pre><pre className="language-json shiki shiki-themes github-light" code="{
  &quot;data&quot;: {
    &quot;project&quot;: {
      &quot;mergeRequest&quot;: {
        &quot;title&quot;: &quot;feat: add OAuth2 support&quot;,
        &quot;reviewers&quot;: {
          &quot;nodes&quot;: [
            { &quot;username&quot;: &quot;dmurphy&quot; },
            { &quot;username&quot;: &quot;sreeves&quot; }
          ]
        }
      }
    }
  }
}

" language="json" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#24292E">{
</span></span><span class="line" line="2"><span style="--shiki-default:#005CC5">  &quot;data&quot;</span><span style="--shiki-default:#24292E">: {
</span></span><span class="line" line="3"><span style="--shiki-default:#005CC5">    &quot;project&quot;</span><span style="--shiki-default:#24292E">: {
</span></span><span class="line" line="4"><span style="--shiki-default:#005CC5">      &quot;mergeRequest&quot;</span><span style="--shiki-default:#24292E">: {
</span></span><span class="line" line="5"><span style="--shiki-default:#005CC5">        &quot;title&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;feat: add OAuth2 support&quot;</span><span style="--shiki-default:#24292E">,
</span></span><span class="line" line="6"><span style="--shiki-default:#005CC5">        &quot;reviewers&quot;</span><span style="--shiki-default:#24292E">: {
</span></span><span class="line" line="7"><span style="--shiki-default:#005CC5">          &quot;nodes&quot;</span><span style="--shiki-default:#24292E">: [
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">            { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;dmurphy&quot;</span><span style="--shiki-default:#24292E"> },
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">            { </span><span style="--shiki-default:#005CC5">&quot;username&quot;</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;sreeves&quot;</span><span style="--shiki-default:#24292E"> }
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">          ]
</span></span><span class="line" line="11"><span style="--shiki-default:#24292E">        }
</span></span><span class="line" line="12"><span style="--shiki-default:#24292E">      }
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">    }
</span></span><span class="line" line="14"><span style="--shiki-default:#24292E">  }
</span></span><span class="line" line="15"><span style="--shiki-default:#24292E">}
</span></span></code></pre><p>Your agent has a single, authenticated entry point to everything GitLab exposes without the token juggling, separate API clients, or configuration
overhead.</p><h2 id="whats-coming-and-your-feedback">What&#39;s coming and your feedback</h2><p>Two improvements we&#39;re actively working on will make <code className="">glab</code> even more useful for agent workflows:</p><p><strong>Agent-aware help text.</strong> Today, <code className="">--help</code> output is written for humansvat a terminal. We&#39;re updating it to surface the non-interactive alternative
for every interactive command, flag which commands support <code className="">--output json</code>, and generally make help a useful resource for agents discovering
capabilities at runtime — not just humans.</p><p><strong>Better machine-readable errors.</strong> When something goes wrong today, agents get the same human-readable error messages as terminal users. We&#39;re
changing that so errors in JSON mode return structured output, giving your agent the information it needs to handle failures gracefully, retry intelligently, or surface the right context back to you.</p><p>Both of these are in active development. If you&#39;re already using <code className="">glab</code> with an AI tool, you&#39;re exactly the audience we want feedback from.</p><ul><li><strong>What friction are you hitting?</strong> Commands that don&#39;t behave well in agent contexts, error messages that aren&#39;t actionable, gaps in JSON output
coverage. We want to know.</li><li><strong>What workflows have you unlocked?</strong> Real usage patterns help us prioritize what to build next.</li></ul><p>Join the discussion in <a href="https://gitlab.com/gitlab-org/cli/-/issues/8177" rel="">our feedback issue</a> — that&#39;s where we&#39;re shaping the roadmap for agent-friendliness, and where your input will have the most direct impact. If you&#39;ve found a specific gap, <a href="https://gitlab.com/gitlab-org/cli/-/issues/new" rel="">open an issue</a>. If you&#39;ve got a fix in mind, contributions are welcome. Visit <a href="https://gitlab.com/gitlab-org/cli/-/blob/main/CONTRIBUTING.md" rel="">CONTRIBUTING.md</a> to get started.</p><p>The GitLab CLI has always been about giving developers more control over their workflow. As AI becomes a bigger part of how we all work, that means making <code className="">glab</code> the best possible interface between your AI tools and your GitLab projects. We&#39;re just getting started and we&#39;d love to build the next part with you.</p><style>html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}</style>]]></content>
        <author>
            <name>Kai Armstrong</name>
            <uri>https://about.gitlab.com/blog/authors/kai-armstrong/</uri>
        </author>
        <published>2026-04-27T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[curl removed from Omnibus-GitLab FIPS packages in 19.0]]></title>
        <id>https://about.gitlab.com/blog/curl-removed-from-omnibus-gitlab-fips-packages-in-19-0/</id>
        <link href="https://about.gitlab.com/blog/curl-removed-from-omnibus-gitlab-fips-packages-in-19-0/"/>
        <updated>2026-04-24T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Starting with Omnibus-GitLab 19.0 (and the subsequent patch release to existing supported versions), FIPS packages will no longer include a GitLab-built version of curl. Instead, they will use the curl package provided by the customer’s Linux distribution, in the same way that FIPS packages already use the distribution&#39;s OpenSSL.</p><h2 id="why-is-this-change-happening">Why is this change happening?</h2><p>This change is necessary because curl 8.18.0 deprecated compilation against OpenSSL 1.x, which prevents us from continuing our previous approach on Amazon Linux 2 and AlmaLinux 8 (affecting RHEL 8 customers). GitLab provides most dependencies for Omnibus-GitLab, but in FIPS packages we link to the distribution&#39;s cryptographic libraries rather than bundling our own — and we are now extending that model to curl.</p><p>For maintainability and security reasons, we are applying this change to all FIPS packages, including distributions with OpenSSL 3.0 or later. All FIPS customers are affected.</p><h2 id="what-do-i-need-to-do">What do I need to do?</h2><h3 id="gitlab-self-managed">GitLab Self-Managed</h3><p>GitLab 19.0 will be available starting on May 21, 2026.</p><blockquote><p>Learn more about the <a href="https://about.gitlab.com/releases/" rel="">release schedule</a>.</p></blockquote><p>Starting with the 19.0 Omnibus-GitLab FIPS package, the bundled curl will be removed and replaced with the curl provided by the customer&#39;s Linux distribution. The customer&#39;s GitLab instance will continue to work as expected. This change has no other impact and doesn&#39;t require any immediate action.</p><h2 id="important-implication">Important implication</h2><p>GitLab will no longer be responsible for shipping security updates to curl specifically in FIPS packages, and it will be up to the customer to keep their own OS&#39;s curl up to date to receive fixes/security patches. Scanner findings for curl will now reflect the host OS package rather than a GitLab-bundled version. This is consistent with how OpenSSL is already handled in FIPS environments.</p><h2 id="what-do-i-do-if-i-still-have-problems">What do I do if I still have problems?</h2><p>If you need assistance, please open an issue in the <a href="https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/new?issue&amp;issuable_template=Bug" rel="">omnibus-gitlab issue tracker</a>.</p>]]></content>
        <author>
            <name>Adam Chu</name>
            <uri>https://about.gitlab.com/blog/authors/adam-chu/</uri>
        </author>
        <published>2026-04-24T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab AI Hackathon 2026: Meet the winners]]></title>
        <id>https://about.gitlab.com/blog/gitlab-ai-hackathon-2026-meet-the-winners/</id>
        <link href="https://about.gitlab.com/blog/gitlab-ai-hackathon-2026-meet-the-winners/"/>
        <updated>2026-04-22T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>AI writes code. That is expected now. But planning, security, compliance, and deployments? Those gaps remain. I have run contributor programs for years. I have never seen a community respond to technology like this.</p><p>That is why we opened <a href="https://about.gitlab.com/gitlab-duo-agent-platform/" rel="">GitLab Duo Agent Platform</a> and invited developers worldwide to build AI agents that help teams ship secure software faster. Not chatbots that answer questions, but agents that jump into workflows, respond to events, and act on your behalf. The GitLab AI Hackathon ran from February 9 to March 25, 2026, on Devpost, the hackathon platform. Google Cloud and Anthropic joined as co-sponsors.</p><p>When my team planned this hackathon with Google Cloud and Anthropic, I asked the judges to score four things: technical work, design, potential impact, and idea quality. We hoped for strong turnout. What we got surprised all of us. Nineteen judges spent 18 days reviewing every entry. Google Cloud and Anthropic provided judges, prizes, and cloud access. The community built hundreds of agents and flows because they wanted to solve these problems.</p><p>Nearly 7,000 developers showed up. They built 600+ agents and flows in weeks. The prizes across all categories totaled $65,000 from GitLab, Google Cloud, and Anthropic.</p><p>If you have ever watched a senior engineer leave and take half the team&#39;s knowledge with them, you know why the winning project hit so hard.</p><p>Read on to find out what the community built.</p><h2 id="grand-prize-lore">Grand Prize: LORE</h2><p><a href="https://devpost.com/software/lore-living-organizational-record-engine" rel="">LORE</a>, the Living Organizational Record Engine, uses eight agents with a router that sends each question to the right agent, logic to prevent circular loops in the knowledge graph, a visual dashboard, and carbon tracking. The command-line tool ships with 43 tests (yes, 43 tests in a hackathon project).</p><p>LORE solves a real problem: the knowledge that lives in engineers&#39; heads and walks out the door when they leave. In my experience, a hackathon project with 43 tests is rare. That many tests in a hackathon project tells you something about the team behind it.</p><p>Judge April Guo (Anthropic) wrote: &quot;This feels like a product, not a hackathon project.&quot;</p><h3 id="google-cloud-winners">Google Cloud winners</h3><p><a href="https://devpost.com/software/gitdefender" rel="">Gitdefender</a> won the Google Cloud Grand Prize. It works inside code review workflows, finding and fixing security issues. It spots the bug, writes the fix, and opens the code review. No developer needs to step in.</p><p><a href="https://devpost.com/software/aegis-2m1oq0" rel="">Aegis</a> won the Google Cloud Runner Up. It gives AI-powered explanations for every decision it makes, deployed to Google Cloud and ready for production use.</p><h3 id="anthropic-winners">Anthropic winners</h3><p><a href="https://devpost.com/software/graphdev" rel="">GraphDev</a> won the Anthropic Grand Prize. It maps code links and shows how systems change over time. Judge Aboobacker MK (GitLab) noted it was &quot;in sync with our work on GitLab knowledge graph.&quot; Judge Ayush Billore (GitLab) wrote: &quot;Loved the demo and UX, super useful for understanding how the system evolved and what gets impacted by changes.&quot; You can see the full impact of a change before you make it.</p><p><a href="https://devpost.com/software/pipeheal" rel="">DocSync</a> won the Anthropic Runner Up. It uses three agents: Detector, Writer, and Reviewer. If DocSync is confident in the fix, it opens a code review. If not, it creates an issue for a human to check.</p><h2 id="category-winners">Category winners</h2><h3 id="most-technically-impressive">Most Technically Impressive</h3><p>Database migrations break things. <a href="https://devpost.com/software/time-traveler-w3cxp0" rel="">Time-Traveler</a> creates a safe copy of your production setup, runs the migration against that copy, and reports the result. It runs five agents connected by a bridge, with real Google Cloud deployment, real PostgreSQL migrations, and real data.</p><h3 id="most-impactful">Most Impactful</h3><p><a href="https://devpost.com/software/redagent" rel="">RedAgent</a> checks AI-generated security reports, closing the trust gap between AI findings and developer action. If your team uses AI for security scanning, you know this problem. I have seen teams dismiss AI findings because they could not verify them. RedAgent gives teams a way to check AI output before it reaches developers.</p><h3 id="easiest-to-use">Easiest to Use</h3><p><a href="https://devpost.com/software/launch-control-bgp8az" rel="">Launch Control</a> delivers polished UX and solid infrastructure, and scored well on sustainability too.</p><h2 id="the-sustainability-signal">The sustainability signal</h2><p>Five projects won prizes or bonuses for environmental impact. Software delivery has a carbon cost as CI/CD pipelines, but now LLMs also run compute at scale. We created the Green Agent category to challenge developers to measure and reduce that footprint. Stacy Cline and Kim Buncle from GitLab&#39;s sustainability team helped judge the Green Agent category.</p><h3 id="green-agent-prize">Green Agent prize</h3><p><a href="https://devpost.com/software/greenpipe" rel="">GreenPipe</a> scans CI/CD pipelines for environmental impact and produces carbon footprint reports. Judges Kim Buncle and Rajesh Agadi (Google) both backed the project.</p><h3 id="sustainable-design-bonus">Sustainable Design bonus</h3><p>Sustainable Design bonuses were awarded to the projects with exceptional sustainability practices in their design, from model optimization techniques to energy-efficient architecture choices.</p><ul><li><a href="https://devpost.com/software/bugflow-ai-regression-detective-ci-optimizer" rel="">BugFlow</a> turned one bug report into 10 fixes in 20 minutes.</li><li><a href="https://devpost.com/software/delta-cyber-reasoning-system" rel="">DELTA Cyber Reasoning</a> is automated fuzz testing for security.</li><li><a href="https://devpost.com/software/carbonlint" rel="">CarbonLint</a> applied code analysis to energy use.</li><li><a href="https://devpost.com/software/tfguardian" rel="">TFGuardian</a> features a carbon footprint analyzer, among other agents.</li></ul><p>Congratulations on all the Sustainable Design bonus winners!</p><p>Judge Jens-Joris Decorte (TechWolf) cited the result: Costs dropped from $556 to $18 per month, a 96% carbon cut (that is a $538 monthly saving with a sustainability label on it).</p><h2 id="honorable-mentions-and-the-long-tail">Honorable mentions and the long tail</h2><p>Six projects received honorable mentions:</p><ul><li><a href="https://devpost.com/software/securitymonkey" rel="">SecurityMonkey</a> injects known vulnerabilities into a test branch and scores how well your security scanners catch them.</li><li><a href="https://devpost.com/software/stregent" rel="">stregent</a> monitors CI/CD pipelines and lets developers investigate and merge fixes from WhatsApp without opening a laptop.</li><li><a href="https://devpost.com/software/compliance-sentinel-autonomous-devsecops-governance" rel="">Compliance Sentinel</a> scores every merge request for compliance risk and blocks the merge if critical violations are detected.</li><li><a href="https://devpost.com/software/carbon-tracker-ij25kf" rel="">Carbon Tracker</a> calculates the carbon footprint of each CI/CD pipeline job and posts optimization tips on the merge request.</li><li><a href="https://devpost.com/software/docuguard" rel="">RepoWarden</a> is the first Living Specification Engine, an AI system that captures why code was written, not just what it does.</li><li><a href="https://devpost.com/software/mr-compliance-auditor" rel="">MR Compliance Auditor</a> collects evidence across merge requests, maps it to SOC 2 controls, and streams compliance scores to a live dashboard.</li></ul><p>My favorite quote from the judging came from Luca Chun Lun Lit (Anthropic), who described stregent&#39;s mobile-first approach: &quot;Being able to essentially code from your phone is a next level in the engineering experience.&quot;</p><blockquote><p>Explore the 600+ entries in the <a href="https://gitlab.devpost.com/project-gallery" rel="">project gallery</a>.</p></blockquote><h2 id="what-comes-next">What comes next</h2><p>Every agent in this hackathon worked within a single project. They still delivered impressive results. Some participants ran a local knowledge graph alongside their agents to surface code relationships and dependencies within the repo. LORE captures project history. Gitdefender finds vulnerabilities. Pairing agents with richer local context is already helping contributors build sharper tools. The next hackathon will build on what contributors are already doing with richer context. Sign up on <a href="https://contributors.gitlab.com/" rel="">contributors.gitlab.com</a> to be the first to know when details drop.</p><h2 id="get-started">Get started</h2><p>A special thanks to Lee Tickett (GitLab) and Mattias Michaux (GitLab) for orchestrating the orchestrators and innovators behind this hackathon!</p><p>Thank you to every developer who submitted. Nearly 7,000 of you showed what GitLab Duo Agent Platform can do when a community decides to build. I am proud of what you built here, and I cannot wait to see what you build next.</p><p>Build your own agent on <a href="https://docs.gitlab.com/user/duo_agent_platform/" rel="">GitLab Duo Agent Platform</a>. Browse community-built agents in the <a href="https://docs.gitlab.com/user/duo_agent_platform/ai_catalog/" rel="">AI Catalog</a>. You orchestrate. AI accelerates.</p>]]></content>
        <author>
            <name>Nick Veenhof</name>
            <uri>https://about.gitlab.com/blog/authors/nick-veenhof/</uri>
        </author>
        <published>2026-04-22T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab Patch Release: 18.11.1, 18.10.4, 18.9.6]]></title>
        <id>https://docs.gitlab.com/releases/patches/patch-release-gitlab-18-11-1-released/</id>
        <link href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-18-11-1-released/"/>
        <updated>2026-04-22T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Discover what&#39;s in this latest patch release.</p>]]></content>
        <published>2026-04-22T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab + Amazon: Platform orchestration on a trusted AI foundation]]></title>
        <id>https://about.gitlab.com/blog/gitlab-amazon-platform-orchestration-on-a-trusted-ai-foundation/</id>
        <link href="https://about.gitlab.com/blog/gitlab-amazon-platform-orchestration-on-a-trusted-ai-foundation/"/>
        <updated>2026-04-21T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>If your team runs GitLab and has a strong AWS practice, a new combination of Duo Agent Platform and Amazon Bedrock is just for you. The model is simple: GitLab acts as your orchestration layer to help accelerate your entire software lifecycle with agentic AI, and Bedrock is designed to provide a secure, compliant foundation model layer with AI inference behind the scenes.</p><p>GitLab Duo Agent Platform enables you to handle planning, merge pipelines, security scanning, vulnerability remediation, and more as part of your GitLab workflows, while the GitLab AI Gateway routes model calls to Bedrock (or GitLab-managed Bedrock-backed endpoints, depending on your setup). That means you can build on the identity and access management (IAM) policies, virtual private cloud (VPC) boundaries, regional controls, and cloud spend commitments you already have in AWS.</p><p>If you already use Amazon Bedrock and want AI to help inside the work you already do in GitLab, not in yet another standalone chat tool, this is the pairing for you.</p><p>In this article, we look at the real problem many teams face today: AI is fragmented, data paths are fuzzy, and Bedrock investment gets underused when AI sits outside the software development lifecycle. Then we break down your deployment options for GitLab Duo Agent Platform:</p><ul><li>Integrated with self-hosted models on Amazon Bedrock for GitLab Self-Managed deployments and self-hosted AI gateway</li><li>Integrated with GitLab-operated models on Amazon Bedrock (with GitLab-owned keys) for GitLab Self-Managed deployments and GitLab-hosted AI gateway</li><li>Integrated with GitLab-operated models on Amazon Bedrock (with GitLab-owned keys) for GitLab.com instances and GitLab-hosted AI gateway</li></ul><p>We wrap with a summary on how this approach helps avoid shadow AI and point-tool sprawl without creating a parallel tech stack for AI tooling.</p><h2 id="ai-everywhere-control-nowhere">AI everywhere, control nowhere</h2><p>Somewhere in your company right now, software teams might be using an AI tool that your security team hasn&#39;t approved. Prompt data might be leaving your environment through a path no one has fully mapped. And your organization’s Amazon Bedrock investment might be underused while individual teams expense separate AI tools, pulling workloads and cloud spend away from the platforms you’ve already committed to.</p><p>Instead of being a people problem, this might be an architecture problem. And it surfaces the same three constraints in nearly every enterprise:</p><p><strong>Operational fragmentation.</strong> Each team, or sometimes even an individual developer, picks their own development toolset, including AI tooling and model selection. That fragmentation makes end-to-end governance within the software development lifecycle nearly impossible.</p><p><strong>Security and sovereignty.</strong> Where does prompt and code data actually flow? Who owns the logs?</p><p><strong>Cloud spend optimization.</strong> Commitments to key cloud providers like AWS are diluted as workloads and AI usage drift to point tools outside of customers’ existing agreements.</p><p>GitLab Duo Agent Platform and Amazon Bedrock help solve this together. The division of labor is straightforward: Duo Agent Platform owns the workflow orchestration with agentic AI for software development, Bedrock owns the inference layer and hosts approved foundational models, and your organization has full control over the data and policy boundaries you already defined in AWS. Three jobs, three owners, no fragmentation.</p><h2 id="gitlab-duo-agent-platform-the-agentic-control-plane">GitLab Duo Agent Platform: The agentic control plane</h2><p>GitLab Duo Agent Platform is GitLab&#39;s agentic AI layer: a framework of specialized agents and flows that operate simultaneously and in-parallel, going beyond the traditional stage-based handoffs  and helping automate work across the entire software lifecycle. Rather than a single assistant responding to prompts, Duo Agent Platform enables teams to orchestrate many AI agents asynchronously using unified data and project context, including issues, merge requests, pipelines, and security findings. Linear workflows are turned into coordinated, continuous collaboration between software teams and their AI agents, at scale.</p><p>With that control plane in place, the natural next question is which AI foundation should power these agents. For customers who run GitLab Self-Managed on AWS and need inference traffic, prompt data, and logs to also stay within their AWS environment along with their software lifecycle data, Amazon Bedrock acting as the AI inference layer is the natural fit.</p><h2 id="amazon-bedrock-the-trusted-ai-foundation">Amazon Bedrock: The trusted AI foundation</h2><p>Amazon Bedrock is a fully managed, serverless foundation model layer that runs entirely within your AWS environment. Customer data stays in the customer&#39;s AWS account: inputs and outputs are encrypted in transit and at rest, never shared with model providers, and never used to train base models. Bedrock carries compliance certifications across GDPR, HIPAA, and FedRAMP High, covering many regulated industry requirements out of the box. Teams can also bring fine-tuned models from elsewhere via Custom Model Import and deploy them alongside native Bedrock models through the same infrastructure, without managing separate deployment pipelines. Bedrock Guardrails adds configurable safeguards across all models for content filtering, hallucination detection, and sensitive data protection.</p><p>Together, GitLab Duo Agent Platform and Bedrock consolidate DevSecOps orchestration and AI model governance, helping eliminate the fragmentation that happens when teams roll out AI tools independently.</p><h2 id="choosing-your-deployment-path">Choosing your deployment path</h2><p>The integration delivers the same core GitLab Duo Agent Platform capabilities regardless of how it is deployed. What varies is who runs GitLab, who operates the AI Gateway, and whose Bedrock account the inference runs through. The right pattern depends on where your organization already operates.</p><p>At a high level, the integration has three main components:</p><ul><li><strong>GitLab Duo Agent Platform:</strong> agentic workflows embedded across the software development lifecycle</li><li><strong>AI Gateway (GitLab-managed or self-hosted):</strong> the abstraction layer between Duo Agent Platform and the foundational model backend</li><li><strong>Amazon Bedrock:</strong> the AI model and inference substrate</li></ul><p><img alt="Deployment of GitLab and AWS Bedrock" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1776362365/udmvmv2efpmwtkxgydch.png" /></p><p>Choosing a deployment pattern is informed by where an organization wants to place the levers of control. The patterns below are designed to meet teams where they already are, whether that&#39;s SaaS-first, self-managed for compliance, or all-in on AWS with existing Bedrock investments.</p><table><thead><tr><th align="left">Deployment Model</th><th align="left">GitLab.com instance with GitLab-hosted AI Gateway with GitLab-operated Bedrock models</th><th align="left">GitLab Self-Managed with GitLab-hosted AI Gateway with GitLab-operated Bedrock models</th><th align="left">GitLab Self-Managed  with self-hosted AI Gateway and customer-operated Bedrock models</th></tr></thead><tbody><tr><td align="left"><strong>Ideal if you:</strong></td><td align="left">Are primarily on GitLab.com and don’t want to self-host AI gateway and Bedrock models</td><td align="left">Need GitLab Self-Managed for compliance and operational reasons but don’t want to manage AI layer</td><td align="left">Are AWS-centric with existing Bedrock usage and strict data/control needs</td></tr><tr><td align="left"><strong>Key Benefits</strong></td><td align="left">Fastest, turnkey way to get Duo Agent Platform workflows: GitLab runs GitLab.com, the AI Gateway, integrated with Bedrock AI models.</td><td align="left">Keep GitLab deployed in your own environment while consuming Bedrock models via a GitLab-managed AI Gateway, combining deployment control with simplified AI operations.</td><td align="left">Run GitLab and AI Gateway in your AWS account, reuse existing IAM/VPC/regions, keep logs and data in your environment, and draw Bedrock usage from your existing AWS spend commitments.</td></tr></tbody></table><h2 id="how-customers-use-gitlab-duo-agent-platform-with-amazon-bedrock">How customers use GitLab Duo Agent Platform with Amazon Bedrock</h2><p>Platform teams can use GitLab Duo Agent Platform with Amazon Bedrock to standardize which models handle code suggestions, security analysis, and pipeline remediation. This helps enforce guardrails and logging centrally rather than letting individual teams adopt separate tools independently.</p><p>Security workflows see particular benefit. GitLab Duo Agent Platform agents can propose and validate fixes for security findings within GitLab, helping reduce the manual triage work developers would otherwise handle outside the platform.</p><p>For enterprises already committed to AWS, routing AI workloads through Bedrock from within GitLab enables you to keep developer AI usage aligned with existing cloud agreements rather than generating separate, unplanned spend.</p><h2 id="closing-the-loop">Closing the loop</h2><p>The constraints that slow enterprise AI adoption are often not technical. They are organizational: fragmented tooling, ungoverned data flows, and cloud spend that never consolidates. Those are the problems that can stall AI programs even after the pilots succeed.</p><p>GitLab Duo Agent Platform and Amazon Bedrock help address each one directly. Platform teams get consistent governance, auditability, and standardized paths for AI usage across the software development lifecycle. Development teams get streamlined, agentic workflows that feel native to GitLab. And AWS-centric organizations get to extend their existing Bedrock investment rather than build parallel AI infrastructure alongside it.</p><p>The result is an AI program that scales without fragmenting. Governance and velocity on the same stack, serving the same teams, under policies the organization already owns.</p><blockquote><p>To explore which deployment pattern is right for your organization and how to align GitLab Duo Agent Platform and Amazon Bedrock with your existing AWS strategy, <a href="https://about.gitlab.com/sales/" rel="">contact the GitLab sales team</a> and we’ll help you design and implement the best architecture for your environment. You can also <a href="https://about.gitlab.com/partners/technology-partners/aws/" rel="">visit our AWS partner page</a> to learn more.</p></blockquote>]]></content>
        <author>
            <name>Joe Mann</name>
            <uri>https://about.gitlab.com/blog/authors/joe-mann/</uri>
        </author>
        <author>
            <name>Mark Kriaf</name>
            <uri>https://about.gitlab.com/blog/authors/mark-kriaf/</uri>
        </author>
        <published>2026-04-21T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[What’s new in Git 2.54.0?]]></title>
        <id>https://about.gitlab.com/blog/whats-new-in-git-2-54-0/</id>
        <link href="https://about.gitlab.com/blog/whats-new-in-git-2-54-0/"/>
        <updated>2026-04-20T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>The Git project recently released <a href="https://lore.kernel.org/git/xmqqa4uxsjrs.fsf@gitster.g/T/#u" rel="">Git 2.54.0</a>. Let&#39;s look at a few notable highlights from this release, which includes contributions from the Git team at GitLab.</p><h2 id="pluggable-object-databases">Pluggable Object Databases</h2><p>Git already has the ability to store references with either the &quot;files&quot; backend or with the <a href="https://about.gitlab.com/blog/a-beginners-guide-to-the-git-reftable-format/" rel="">&quot;reftable&quot; backend</a>. This is achieved by having proper abstractions in Git that allows us to have different backends.</p><p>But references are just one of the two important types of data that are stored in repositories, with the other being objects. Objects are stored in the object database, and each object database in turn consists of multiple object sources where objects can be read from or written to. Each object source either stores individual objects as so-called &quot;loose&quot; objects, or compresses multiple objects into a &quot;packfile&quot; in your <code className="">.git/objects</code> directory.</p><p>Until now, however, these sources did not have a proper abstraction boundary, so the storage format for objects is completely hardcoded into Git. But this is finally changing with pluggable object databases! The concept is straightforward and similar to how we did this for references in the past: Instead of having hardcoded code paths for how to store objects, we introduce an abstraction boundary that allows us to have different backends for storing objects.</p><p>While the idea is simple, the implementation is not, as we have hardcoded assumptions about the storage formats used in Git all over the place. In fact, we have started working on this topic in Git 2.48, which was released in January 2025. Initially, we focused on making object-related subsystems self-contained and creating proper subsystems for the existing backends that we had in Git.</p><p>With Git 2.54, we have now reached a milestone: The object database backend is now pluggable. Not all of Git&#39;s functionality is covered yet, but introducing an alternate backend that handles a meaningful subset of operations is now a realistic undertaking.</p><p>For now, only local workflows like creating commits, showing commit graphs, or performing merges will work with such an alternative implementation. This notably excludes anything that interacts with a remote, such as when you want to fetch or push changes. Regardless, this is the culmination of almost two years of work spanning across almost 400 commits that have been merged upstream, and we will of course continue to iterate on this effort.</p><p>So why does this matter? The idea is that it becomes practical to introduce new storage formats into Git. Examples could be:</p><ul><li>A storage format that is able to store large binary files more efficiently
than packfiles do today</li><li>A storage format that is custom-tailored for GitLab to ensure that we can
serve repositories to our users even more efficiently than we currently can</li></ul><p>This is a large-scale effort that is likely to shape the future of Git and GitLab.</p><p><em>This project was led by <a href="https://gitlab.com/pks-gitlab" rel="">Patrick Steinhardt</a>.</em></p><h2 id="easier-editing-of-your-commit-history">Easier editing of your commit history</h2><p>In many software development projects it is common practice for developers to not only polish the code they want to contribute, but to also polish the commit history so that it becomes easy to review. The result is a set of small and atomic commits that each do one thing, with a good commit message that describes the intent of the commit as well as specific nuances.</p><p>Of course, more often than not, these atomic commits are not something that just happens naturally during the development process. Instead, the author of the changes will gain a better understanding of what they are while iterating on them, and the way to split up the commits will become clearer over time. Furthermore, the subsequent review process may result in feedback that requires changes to the crafted commits.</p><p>The consequence of this process is that the developer will have to rewrite their commit history many times during the development process. Historically, Git has allowed for this use case via <a href="https://git-scm.com/docs/git-rebase#_interactive_mode" rel="">interactive rebases</a>. These interactive rebases are an extremely powerful tool: They let you reorder commits, rewrite commit messages, squash multiple commits together, or perform arbitrary edits of any commit.</p><p>But they are also somewhat arcane and hard to understand. The user needs to figure out the base commit for the rebase, they need to understand how to edit a somewhat obscure &quot;instruction sheet,&quot; and they need to be aware of how the stateful rebasing process works. For example, users are presented with an instruction sheet similar to the following when rebasing a topic branch:</p><pre className="language-shell shiki shiki-themes github-light" code="pick b60623f382 # t: detect errors outside of test cases # empty
pick b80cb55882 # t: prepare `test_match_signal ()` calls for `set -e`
pick 5ffe397f30 # t: prepare `test_must_fail ()` for `set -e`
pick 5e9b0cf5e1 # t: prepare `stop_git_daemon ()` for `set -e`
pick 299561e7a2 # t: prepare `git config --unset` calls for `set -e`
pick ed0e7ca2b5 # t: detect errors outside of test cases
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> b60623f382</span><span style="--shiki-default:#6A737D"> # t: detect errors outside of test cases # empty
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> b80cb55882</span><span style="--shiki-default:#6A737D"> # t: prepare `test_match_signal ()` calls for `set -e`
</span></span><span class="line" line="3"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> 5ffe397f30</span><span style="--shiki-default:#6A737D"> # t: prepare `test_must_fail ()` for `set -e`
</span></span><span class="line" line="4"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> 5e9b0cf5e1</span><span style="--shiki-default:#6A737D"> # t: prepare `stop_git_daemon ()` for `set -e`
</span></span><span class="line" line="5"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> 299561e7a2</span><span style="--shiki-default:#6A737D"> # t: prepare `git config --unset` calls for `set -e`
</span></span><span class="line" line="6"><span style="--shiki-default:#6F42C1">pick</span><span style="--shiki-default:#032F62"> ed0e7ca2b5</span><span style="--shiki-default:#6A737D"> # t: detect errors outside of test cases
</span></span></code></pre><p>So while interactive rebases are powerful, they are also quite intimidating for the average user.</p><p>It doesn&#39;t have to be this way, though. Tools like <a href="https://www.jj-vcs.dev/latest/" rel="">Jujutsu</a> provide interfaces that are much easier to use compared to Git, as you can for example simply execute <code className="">jj split</code> to split up a commit into two commits. With Git and interactive rebases, this use case requires a lot of different steps with confusing command line arguments.</p><p>We have thus taken inspiration from Jujutsu and have introduced a new git-history(1) command into Git that is the foundation for better history editing. For now, this command has two subcommands:</p><ul><li><code className="">git history reword</code> allows you to easily rewrite a commit message. You simply
give it the commit whose message you want to reword, Git asks you for the new
commit message, and that&#39;s it.</li><li><code className="">git history split</code> allows you to split up a commit into two, which is
inspired by <code className="">jj split</code>. You give it a commit, Git asks you which changes to
stage into which commit and for the two commit messages, and then you&#39;re done.</li></ul><p>This is of course only a start, and we want to add additional subcommands over time. For example:</p><ul><li><code className="">git history fixup</code> to take staged changes and automatically amend them to a
specific commit</li><li><code className="">git history drop</code> to remove a commit</li><li><code className="">git history reorder</code> to reorder the sequence of commits</li><li><code className="">git history squash</code> to squash a range of commits</li></ul><p>But that&#39;s not all! In addition to making history editing easy, this new command also knows to automatically rebase all of your local branches that previously included this commit. So that means that you can even edit a commit that is not on the current branch, and all branches that contain the commit will be rewritten.</p><p>It may seem puzzling at first that Git is automatically rebasing dependent branches, as that is a significant diversion from how git-rebase(1) works. But this is part of a bigger effort to bring better support for Stacked Diffs to Git, which are a way to create a series of multiple dependent branches that can be reviewed independently, but that together work towards a bigger goal.</p><p><em>This project was led by <a href="https://gitlab.com/pks-gitlab" rel="">Patrick Steinhardt</a> with support from <a href="https://github.com/newren" rel="">Elijah Newren</a>.</em></p><h2 id="a-native-replacement-for-git-sizer1">A native replacement for git-sizer(1)</h2><p>The size of a Git repository is an important factor that determines how well Git and GitLab can handle it. But size alone is not the only factor, as the performance of a repository is ultimately a combination of multiple different dimensions:</p><ul><li>The depth of the commit history</li><li>The shape of the directory structure</li><li>The size of files stored in the repository</li><li>The number of references</li></ul><p>These are only some of the dimensions one needs to consider when trying to predict whether Git will be able to handle a repository well.</p><p>But while it is clear that the mere repository size is insufficient, Git itself does not provide any tooling that gives the user an easy overview of these metrics. Instead, users are forced to rely on third-party tools like <a href="https://github.com/github/git-sizer" rel="">git-sizer(1)</a> to fill this gap. This tool does an excellent job at surfacing this information, but it is not part of Git itself and thus needs to be installed separately.</p><p>Observability of repository internals is critical to us at GitLab, so we introduced a <a href="https://about.gitlab.com/blog/whats-new-in-git-2-52-0/#new-subcommand-for-git-repo1-to-display-repository-metrics" rel="">new <code className="">git repo structure</code> command into Git 2.52</a> to display repository metrics, which we have extended in Git 2.53 to <a href="https://about.gitlab.com/blog/whats-new-in-git-2-53-0/#more-data-collected-in-git-repo-structure" rel="">show inflated and disk sizes for objects by type</a>.</p><p>In Git 2.54, we are now iterating some more on this command so that we don&#39;t only show the overall size, but also show the largest objects by type:</p><pre className="language-shell shiki shiki-themes github-light" code="$ git clone https://gitlab.com/git-scm/git.git
$ cd git
$ git repo structure
Counting objects: 410445, done.
| Repository structure      | Value       |
| ------------------------- | ----------- |
| * References              |             |
|   * Count                 |    1.01 k   |
|     * Branches            |       1     |
|     * Tags                |    1.00 k   |
|     * Remotes             |       9     |
|     * Others              |       0     |
|                           |             |
| * Reachable objects       |             |
|   * Count                 |  410.45 k   |
|     * Commits             |   83.99 k   |
|     * Trees               |  164.46 k   |
|     * Blobs               |  161.00 k   |
|     * Tags                |    1.00 k   |
|   * Inflated size         |    7.46 GiB |
|     * Commits             |   57.53 MiB |
|     * Trees               |    2.33 GiB |
|     * Blobs               |    5.07 GiB |
|     * Tags                |  737.48 KiB |
|   * Disk size             |  181.37 MiB |
|     * Commits             |   33.11 MiB |
|     * Trees               |   40.58 MiB |
|     * Blobs               |  107.11 MiB |
|     * Tags                |  582.67 KiB |
|                           |             |
| * Largest objects         |             |
|   * Commits               |             |
|     * Maximum size    [1] |   17.23 KiB |
|     * Maximum parents [2] |      10     |
|   * Trees                 |             |
|     * Maximum size    [3] |   58.85 KiB |
|     * Maximum entries [4] |    1.18 k   |
|   * Blobs                 |             |
|     * Maximum size    [5] | 1019.51 KiB |
|   * Tags                  |             |

|     * Maximum size    [6] |    7.13 KiB |

[1] f6ecb603ff8af608a417d7724727d6bc3a9dbfdf
[2] 16d7601e176cd53f3c2f02367698d06b85e08879
[3] 203ee97047731b9fd3ad220faa607b6677861a0d
[4] 203ee97047731b9fd3ad220faa607b6677861a0d
[5] aa96f8bc361fd84a1459440f1e7de02ab0dc3543
[6] 07e38db6a5a03690034d27104401f6c8ea40f1fc
" language="shell" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6F42C1">$</span><span style="--shiki-default:#032F62"> git</span><span style="--shiki-default:#032F62"> clone</span><span style="--shiki-default:#032F62"> https://gitlab.com/git-scm/git.git
</span></span><span class="line" line="2"><span style="--shiki-default:#6F42C1">$</span><span style="--shiki-default:#032F62"> cd</span><span style="--shiki-default:#032F62"> git
</span></span><span class="line" line="3"><span style="--shiki-default:#6F42C1">$</span><span style="--shiki-default:#032F62"> git</span><span style="--shiki-default:#032F62"> repo</span><span style="--shiki-default:#032F62"> structure
</span></span><span class="line" line="4"><span style="--shiki-default:#6F42C1">Counting</span><span style="--shiki-default:#032F62"> objects:</span><span style="--shiki-default:#032F62"> 410445,</span><span style="--shiki-default:#032F62"> done.
</span></span><span class="line" line="5"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> Repository</span><span style="--shiki-default:#032F62"> structure</span><span style="--shiki-default:#D73A49">      |</span><span style="--shiki-default:#6F42C1"> Value</span><span style="--shiki-default:#D73A49">       |
</span></span><span class="line" line="6"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> -------------------------</span><span style="--shiki-default:#D73A49"> |</span><span style="--shiki-default:#6F42C1"> -----------</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="7"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> *</span><span style="--shiki-default:#032F62"> References</span><span style="--shiki-default:#D73A49">              |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="8"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Count</span><span style="--shiki-default:#D73A49">                 |</span><span style="--shiki-default:#6F42C1">    1.01</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="9"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Branches</span><span style="--shiki-default:#D73A49">            |</span><span style="--shiki-default:#6F42C1">       1</span><span style="--shiki-default:#D73A49">     |
</span></span><span class="line" line="10"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Tags</span><span style="--shiki-default:#D73A49">                |</span><span style="--shiki-default:#6F42C1">    1.00</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="11"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Remotes</span><span style="--shiki-default:#D73A49">             |</span><span style="--shiki-default:#6F42C1">       9</span><span style="--shiki-default:#D73A49">     |
</span></span><span class="line" line="12"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Others</span><span style="--shiki-default:#D73A49">              |</span><span style="--shiki-default:#6F42C1">       0</span><span style="--shiki-default:#D73A49">     |
</span></span><span class="line" line="13"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#D73A49">                           |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="14"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> *</span><span style="--shiki-default:#032F62"> Reachable</span><span style="--shiki-default:#032F62"> objects</span><span style="--shiki-default:#D73A49">       |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="15"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Count</span><span style="--shiki-default:#D73A49">                 |</span><span style="--shiki-default:#6F42C1">  410.45</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="16"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Commits</span><span style="--shiki-default:#D73A49">             |</span><span style="--shiki-default:#6F42C1">   83.99</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="17"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Trees</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">  164.46</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="18"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Blobs</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">  161.00</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="19"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Tags</span><span style="--shiki-default:#D73A49">                |</span><span style="--shiki-default:#6F42C1">    1.00</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="20"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Inflated</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#D73A49">         |</span><span style="--shiki-default:#6F42C1">    7.46</span><span style="--shiki-default:#032F62"> GiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="21"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Commits</span><span style="--shiki-default:#D73A49">             |</span><span style="--shiki-default:#6F42C1">   57.53</span><span style="--shiki-default:#032F62"> MiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="22"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Trees</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">    2.33</span><span style="--shiki-default:#032F62"> GiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="23"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Blobs</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">    5.07</span><span style="--shiki-default:#032F62"> GiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="24"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Tags</span><span style="--shiki-default:#D73A49">                |</span><span style="--shiki-default:#6F42C1">  737.48</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="25"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Disk</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#D73A49">             |</span><span style="--shiki-default:#6F42C1">  181.37</span><span style="--shiki-default:#032F62"> MiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="26"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Commits</span><span style="--shiki-default:#D73A49">             |</span><span style="--shiki-default:#6F42C1">   33.11</span><span style="--shiki-default:#032F62"> MiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="27"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Trees</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">   40.58</span><span style="--shiki-default:#032F62"> MiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="28"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Blobs</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#6F42C1">  107.11</span><span style="--shiki-default:#032F62"> MiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="29"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Tags</span><span style="--shiki-default:#D73A49">                |</span><span style="--shiki-default:#6F42C1">  582.67</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="30"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#D73A49">                           |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="31"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> *</span><span style="--shiki-default:#032F62"> Largest</span><span style="--shiki-default:#032F62"> objects</span><span style="--shiki-default:#D73A49">         |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="32"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Commits</span><span style="--shiki-default:#D73A49">               |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="33"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#24292E">    [1] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   17.23</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="34"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> parents</span><span style="--shiki-default:#24292E"> [2] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">      10</span><span style="--shiki-default:#D73A49">     |
</span></span><span class="line" line="35"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Trees</span><span style="--shiki-default:#D73A49">                 |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="36"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#24292E">    [3] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   58.85</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="37"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> entries</span><span style="--shiki-default:#24292E"> [4] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">    1.18</span><span style="--shiki-default:#032F62"> k</span><span style="--shiki-default:#D73A49">   |
</span></span><span class="line" line="38"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Blobs</span><span style="--shiki-default:#D73A49">                 |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="39"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#24292E">    [5] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1"> 1019.51</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="40"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">   *</span><span style="--shiki-default:#032F62"> Tags</span><span style="--shiki-default:#D73A49">                  |</span><span style="--shiki-default:#D73A49">             |
</span></span><span class="line" line="41"><span emptyLinePlaceholder>
</span></span><span class="line" line="42"><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">     *</span><span style="--shiki-default:#032F62"> Maximum</span><span style="--shiki-default:#032F62"> size</span><span style="--shiki-default:#24292E">    [6] </span><span style="--shiki-default:#D73A49">|</span><span style="--shiki-default:#6F42C1">    7.13</span><span style="--shiki-default:#032F62"> KiB</span><span style="--shiki-default:#D73A49"> |
</span></span><span class="line" line="43"><span emptyLinePlaceholder>
</span></span><span class="line" line="44"><span style="--shiki-default:#24292E">[1] </span><span style="--shiki-default:#6F42C1">f6ecb603ff8af608a417d7724727d6bc3a9dbfdf
</span></span><span class="line" line="45"><span style="--shiki-default:#24292E">[2] 16d7601e176cd53f3c2f02367698d06b85e08879
</span></span><span class="line" line="46"><span style="--shiki-default:#24292E">[3] 203ee97047731b9fd3ad220faa607b6677861a0d
</span></span><span class="line" line="47"><span style="--shiki-default:#24292E">[4] 203ee97047731b9fd3ad220faa607b6677861a0d
</span></span><span class="line" line="48"><span style="--shiki-default:#24292E">[5] aa96f8bc361fd84a1459440f1e7de02ab0dc3543
</span></span><span class="line" line="49"><span style="--shiki-default:#24292E">[6] 07e38db6a5a03690034d27104401f6c8ea40f1fc
</span></span></code></pre><p>With this information we&#39;re now almost feature-complete as compared to git-sizer(1). We&#39;re not done yet, though — we plan to eventually add additional features such as:</p><ul><li>Severity levels as they exist in git-sizer(1)</li><li>Graphs that show you the distribution of object sizes</li><li>The ability to scan objects reachable via a subset of references</li></ul><p><em>This project was led by <a href="https://gitlab.com/justintobler" rel="">Justin Tobler</a>.</em></p><h2 id="new-infrastructure-for-repository-maintenance">New infrastructure for repository maintenance</h2><p>Whenever you write data into a Git repository you will typically end up adding more loose objects. Left unmanaged, this leads to a large number of separate files in your <code className="">.git/objects/</code> directory, which slows down several operations that want to access many objects at once. Git thus regularly packs these objects into &quot;packfiles&quot; to ensure good performance.</p><p>This isn&#39;t the only data structure that may become inefficient over time: Updating references may create loose references, reflogs will need trimming, worktrees may become stale, and caches like commit-graphs need to be refreshed regularly.</p><p>All of these tasks have historically been managed by <a href="https://git-scm.com/docs/git-gc" rel="">git-gc(1)</a>. However, this tool has a monolithic architecture, where it basically executes all of the tasks required in sequential order. This foundation is hard to extend and doesn&#39;t give the end user much flexibility in case they want to slightly modify how housekeeping is performed.</p><p>The Git project introduced the new <a href="https://git-scm.com/docs/git-maintenance" rel="">git-maintenance(1)</a> tool in Git 2.29. In contrast to git-gc(1), git-maintenance(1) is not monolithic but is instead structured around tasks. These tasks are freely configurable by the user so that the user can control which tasks are running, giving them much more fine-grained control over repository maintenance.</p><p>Eventually, Git has migrated to use git-maintenance(1) by default. But in the beginning, the only task that was default-enabled was the git-gc(1) task, which as you might have guessed, simply executes <code className="">git gc</code>. To manually run maintenance using this new command you can execute <code className="">git maintenance run</code>, but Git knows to execute this automatically after several other commands.</p><p>Over the last couple releases we have implemented all the individual tasks that are supported by git-gc(1) in git-maintenance(1) to ensure that we have feature parity between these two tools.</p><p>Furthermore, we have implemented a new task that uses Git&#39;s modern architecture for repacking objects with <a href="https://git-scm.com/docs/git-repack#Documentation/git-repack.txt---geometricfactor" rel="">geometric compaction</a>.
Geometric compaction is a much better fit for large monorepos, and with our efforts to make them work well with partial clones <a href="https://about.gitlab.com/blog/whats-new-in-git-2-53-0/#geometric-repacking-support-with-promisor-remotes" rel="">that landed in Git 2.53</a> they are now a full replacement for our previous repacking strategy in Git.</p><p>In Git 2.54, we have now reached another significant milestone: Instead of using the git-gc(1)-based strategy by default, we are now using geometric repacking with fine-grained individual maintenance tasks! Besides being more efficient for large monorepos, it also ensures that we have an easier foundation to iterate on going forward.</p><p><em>The git-maintenance(1) infrastructure was originally implemented by <a href="https://github.com/derrickstolee" rel="">Derrick Stolee</a> and geometric maintenance was introduced by <a href="https://github.com/ttaylorr" rel="">Taylor Blau</a>. The effort to introduce the new fine-grained tasks and migrate to the new maintenance strategy was led by <a href="https://gitlab.com/pks-gitlab" rel="">Patrick Steinhardt</a>.</em></p><h2 id="read-more">Read more</h2><p>This article highlighted just a few of the contributions made by GitLab and the wider Git community for this latest release. You can learn about these from the <a href="https://lore.kernel.org/git/xmqqa4uxsjrs.fsf@gitster.g/T/#u" rel="">official release announcement</a> of the Git project. Also, check out our <a href="https://about.gitlab.com/blog/tags/git/" rel="">previous Git release blog posts</a> to see other past highlights of contributions from GitLab team members.</p><style>html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}</style>]]></content>
        <author>
            <name>Patrick Steinhardt</name>
            <uri>https://about.gitlab.com/blog/authors/patrick-steinhardt/</uri>
        </author>
        <published>2026-04-20T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Prepare your pipeline for AI-discovered zero-days]]></title>
        <id>https://about.gitlab.com/blog/prepare-your-pipeline-for-ai-discovered-zero-days/</id>
        <link href="https://about.gitlab.com/blog/prepare-your-pipeline-for-ai-discovered-zero-days/"/>
        <updated>2026-04-20T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Anthropic&#39;s <a href="https://red.anthropic.com/2026/mythos-preview/" rel="">Mythos Preview model</a> recently identified thousands of zero-day vulnerabilities across every major operating system and web browser, including an OpenBSD bug that went undetected for 27 years. In testing, Mythos autonomously chained four vulnerabilities into a working browser exploit that escaped its sandbox. Anthropic is restricting access to Mythos, but the company’s head of offensive cyber research expects threats to have comparable tooling within six to twelve months.</p><p>The defender side of the equation hasn&#39;t kept pace. One third of exploited Common Vulnerabilities and Exposures (CVEs) in the first half of 2025 showed activity on or before disclosure day, before most teams even know there&#39;s something to patch. AI is compressing that window further, accelerating attackers and flooding teams with whitehat disclosures faster than they can triage. Defender tooling has improved, but most organizations can&#39;t operationalize it fast enough to close the gap between discovery and exploitation.</p><p>When the window between disclosure and exploitation is measured in hours, the security team can&#39;t be the last line of defense. Security has to run where code enters the system: in the pipeline, on every merge request, enforced by policy. The fixes that can be automated should be. The ones that can&#39;t need to reach the right human faster than they do today.</p><h2 id="known-vulnerabilities-are-already-outpacing-remediation">Known vulnerabilities are already outpacing remediation</h2><p>The bottleneck isn&#39;t detection, it&#39;s acting at scale on what teams already know. Sixty percent of breaches in the 2025 Verizon DBIR involved exploiting known vulnerabilities where a patch was already available. Teams couldn’t close them in time.</p><p>The backlog was untenable before Mythos. Developers spend <a href="https://about.gitlab.com/resources/developer-survey/" rel="">11 hours per month remediating vulnerabilities</a> post-release instead of shipping new work. Over half of organizations have at least one open internet-facing vulnerability, and the median time to close half of those is 361 days. Exploitation takes hours, while remediation takes months.</p><p>AI-assisted development is widening the gap, and stakeholders know it. By June 2025, AI-generated code was adding over 10,000 new security findings per month across Fortune 50 repositories, a 10x jump from six months earlier. Georgia Tech identified 34 <a href="https://research.gatech.edu/bad-vibes-ai-generated-code-vulnerable-researchers-warn" rel="">CVEs attributable to AI-generated code</a> in March 2026, up from 6 in January, and that count reflects only the ones where AI authorship is clear. AI coding assistants hallucinate package names, reach for outdated patterns, and copy insecure examples from training data. More code, more dependencies, and more vulnerabilities per line are generated faster than security teams can review them.</p><p>Defenders need to harness frontier AI models, too — not bolted onto the SDLC as external tooling, but running inside the same policies, approvals, and audit trail as the rest of the team.</p><h2 id="security-at-the-speed-of-ai-coding">Security at the speed of AI coding</h2><p>When a critical CVE drops, how quickly can your team confirm which projects are affected? How many tools does an alert cross before a developer can submit a fix?</p><p>The teams that benefit most from AI already have policies, enforcement, and controls embedded in their development workflows. AI amplifies that foundation. It doesn&#39;t replace it.</p><p><strong>Enforcement at the point of change.</strong> As exploitation windows compress, every line of code entering a repository needs to pass through a defined set of controls. Not a separate review, in a different tool, by a different team. Organizations need the ability to enforce security policies across every group and project, with the merge request as the enforcement point. Policies defined once, applied everywhere, with exceptions reviewed, approved, and logged.</p><p><strong>Simple issues caught before the merge request, not during.</strong> Hardcoded secrets, known-vulnerable imports, and deprecated API calls can be flagged in the IDE before a developer pushes a commit. Catching them at authoring time means fewer findings blocking the MR, so review cycles go to the findings that require cross-component context: reachability, exploitability, and architectural risk.</p><p><strong>Triage automated by default, not by exception.</strong> Embedding security into every merge request creates a volume problem. More scans, more findings, more noise reaching developers who aren’t trained to distinguish a reachable critical from a theoretical one. AI must handle false positive detection, reachability, exploitability context, and severity assessment before a developer sees the finding, so the findings they see actually warrant their time.</p><p><strong>Remediation governed like any other change.</strong> AI-based remediation compresses the timeline for closing vulnerabilities, but every generated fix must move through the same governance as a human-authored change: policies enforce scans, the right reviewers approve, and evidence is recorded. GitLab’s automated remediation capability proposes each fix in a merge request with a confidence score. The MR records which policy applied, which scans ran, what they found, and who approved. Human code and AI-generated code move through the same process, with the same audit trail.</p><h2 id="what-a-ready-pipeline-looks-like">What a ready pipeline looks like</h2><p>Here&#39;s how these pieces work together when a high-severity vulnerability is discovered and the clock is running.</p><p>A proof-of-concept exploit for a vulnerability in a popular open-source package appears on a security mailing list. There’s no CVE, no National Vulnerability Database (NVD) entry, and no scanner signature yet. The security team finds out the usual way: someone shares it in Slack.</p><p>A security engineer asks the security agent if the package is in use, which projects have affected versions, and whether any vulnerable call paths are reachable in production. The agent checks the dependency graph for every project, matches the affected versions and entry points from the disclosure, and returns a ranked list of exposed projects with details about reachability. There’s no need to search through repositories by hand or wait for a scanner update. The question, &quot;Are we exposed?&quot; is answered in minutes.</p><p>The engineer starts a remediation campaign for every exposed project. The remediation agent suggests fixes: version updates where a patched release is available, and targeted call-path patches where it is not. Scan execution policies are already in place for projects tagged SOC 2. The engineer hardens the rules to block merges on any merge request that introduces or keeps the affected dependency, and an approval policy now requires security sign-off on every fix. The agent&#39;s first proposed patch fails the pipeline when an integration test catches a regression. The agent revises the patch based on the test failure, and the second attempt passes. Developers review the changes, security signs off under the stricter policy, and merges proceed across the campaign.</p><p>At the next audit review, the security team presents a report showing how policies were enforced and risks were reduced during the campaign. It includes scan results, policies applied, approvers, and merge timestamps for every MR in every affected project. The evidence was automatically generated in flight, not assembled after the fact.</p><h2 id="close-the-gaps-now">Close the gaps now</h2><p>Mythos exists today, and comparable models will be in attacker hands within a year. Every month between now and then is a chance to strengthen your software supply chain.</p><p>Ask these questions about your pipeline:</p><ul><li>How do you enforce that security scans run on every merge request, not just the projects where teams configured them?</li><li>If a compromised package entered your dependency tree today, would your pipeline catch it before build?</li><li>When a scanner flags a critical finding, how many tool boundaries does it cross before a developer starts the fix?</li><li>If an AI agent proposed a code fix for a vulnerability, what process would that fix go through before reaching production, and is that process auditable?</li><li>When auditors ask for evidence that a specific policy was enforced on a specific change, how long does it take to produce?</li></ul><p>If the answers expose gaps, address them now. <a href="https://about.gitlab.com/sales/" rel="">Talk to a GitLab solutions architect</a> about the role of security governance in your development lifecycle.</p>]]></content>
        <author>
            <name>Omer Azaria</name>
            <uri>https://about.gitlab.com/blog/authors/omer-azaria/</uri>
        </author>
        <published>2026-04-20T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitHub Copilot's new policy for AI training is a governance wake-up call]]></title>
        <id>https://about.gitlab.com/blog/github-copilots-new-policy-for-ai-training-is-a-governance-wake-up-call/</id>
        <link href="https://about.gitlab.com/blog/github-copilots-new-policy-for-ai-training-is-a-governance-wake-up-call/"/>
        <updated>2026-04-20T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>GitHub recently <a href="https://github.blog/news-insights/company-news/updates-to-github-copilot-interaction-data-usage-policy/" rel="">announced</a> a significant change to how it handles data from Copilot users. Starting April 24, 2026, interaction data from Copilot Free, Pro, and Pro+ users, including inputs, outputs, code snippets, and associated context, will be used to train AI models by default, unless users actively opt out. Copilot Business and Enterprise customers are exempt under existing contract terms.</p><p>For organizations in regulated industries, including finance, healthcare, defense, and public sector, the policy shift raises questions that go beyond individual developer preferences. It forces a harder look at a question that engineering and security leaders should be asking every AI vendor in their stack: Do you train on our code?</p><p>GitLab&#39;s answer is no. GitLab does not train AI models on customer code at any tier, and AI vendors are contractually prohibited from using customer inputs or outputs for their own purposes. The <a href="https://about.gitlab.com/ai-transparency-center/" rel="">GitLab AI Transparency Center</a> makes that commitment auditable: a single location documenting which models power which features, how data is handled, subprocessor relationships, and data retention periods. The GitLab AI Transparency Center also lists the compliance status of each feature, including confirmation that GitLab&#39;s current AI features do not qualify as high-risk systems under the EU AI Act. It&#39;s a standard GitLab CEO Bill Staples has consistently <a href="https://www.linkedin.com/posts/williamstaples_gitlab-1810-agentic-ai-now-open-to-even-activity-7443280763715985408-aHxf?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABsu7EUBcb_a1-JHKS9RC0B5rf8Ye-5XM60" rel="">reiterated</a> and one reflected in GitLab&#39;s mission and <a href="https://trust.gitlab.com/" rel="">Trust Center</a>.</p><h2 id="what-the-policy-change-actually-means">What the policy change actually means</h2><p>GitHub&#39;s announcement also specifies that the data may be shared with GitHub affiliates, including Microsoft, for AI development purposes.</p><p>A policy change of this nature forces organizations to re-examine their AI governance posture, audit their Copilot license tiers, and confirm that the right controls are configured across their teams.</p><h2 id="why-ai-governance-matters-in-regulated-environments">Why AI governance matters in regulated environments</h2><p>Source code is often among an organization&#39;s most sensitive intellectual property. It may contain references to internal systems, reflect proprietary business logic, or touch data flows governed by strict retention and access policies. When that code passes through an AI assistant, questions about training data usage, model vendor relationships, and data residency become compliance concerns.</p><p>The exposure is particularly acute for financial services firms that have invested in proprietary algorithms, fraud detection logic, credit risk models, underwriting rules, trading strategies. When AI tooling processes that code and uses it to train models serving competitors, vendor data practices become an IP concern.</p><p>Financial institutions operating under <a href="https://www.federalreserve.gov/supervisionreg/srletters/sr1107.htm" rel="">the Federal Reserve&#39;s Supervisory Guidance on Model Risk Management (SR 11-7) and the</a> <a href="https://eur-lex.europa.eu/eli/reg/2022/2554/oj/eng" rel="">Digital Operational Resilience Act (DORA)</a> are required to maintain documented, auditable oversight of third-party technology providers, including understanding how those providers handle data. Third-party AI tools used in development workflows increasingly fall within the scope of model risk oversight, and material changes to vendor data practices require updated documentation.</p><p>In the public sector, <a href="https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final" rel="">the National Institute of Standards and Technology Special Publication 800-53 (NIST 800-53)</a> and the <a href="https://www.cisa.gov/topics/cyber-threats-and-advisories/federal-information-security-modernization-act" rel="">Federal Information Security Modernization Act (FISMA)</a> establish that sensitive or classified code must never leave a controlled boundary. For U.S. Department of Defense and intelligence community environments in particular, a vendor&#39;s default data posture is an operational concern. In healthcare, <a href="https://www.hhs.gov/hipaa/index.html" rel="">the Health Insurance Portability and Accountability Act (HIPAA)</a> governs how patient-adjacent data is handled by third parties, and development environments that touch clinical systems increasingly fall within that scope.</p><p>Across all of these contexts, the common thread is the same: A vendor policy that changes data usage defaults, requires individual opt-out, and offers different protections depending on account tier introduces exactly the kind of uncontrolled variable that compliance teams cannot afford.</p><h2 id="what-regulated-industries-actually-need-from-ai-vendors">What regulated industries actually need from AI vendors</h2><p>Regulated organizations have largely moved past debating whether to adopt AI in development workflows. The focus now is on doing so in a way they can defend to regulators, boards, and customers. That shift has surfaced a consistent set of requirements regardless of sector.</p><p><strong>Contractual certainty.</strong> Regulated firms need to know, with specificity, what happens to their data. A clear, documented, unconditional commitment is what&#39;s required, not something that varies by plan or requires action before a deadline.</p><p><strong>Auditability.</strong> Model risk management frameworks require organizations to understand and validate the AI systems they deploy, including the training data behind those models and the third parties involved in their development. Vendors who cannot answer these questions create documentation risk for the organizations relying on them.</p><p><strong>Separation from vendor incentives.</strong> When an AI vendor trains models on customer usage data, code and workflows become inputs to a system that also serves competitors. For institutions with proprietary trading logic, underwriting models, or fraud detection systems, that&#39;s a genuine IP exposure.</p><h2 id="gitlabs-position-on-ai-data-governance">GitLab&#39;s position on AI data governance</h2><p>GitLab does not use customer code to train AI models. This commitment applies at every tier, and AI vendors are contractually prohibited from using inputs or outputs associated with GitLab customers for their own purposes.</p><p>This is a deliberate architectural and policy choice, not a feature of a particular pricing tier. As GitLab&#39;s <a href="https://about.gitlab.com/blog/why-enterprise-independence-matters-more-than-ever-in-devsecops/" rel="">post on enterprise independence</a> notes, data governance has become &quot;an increasingly critical factor in enterprise technology decisions, driven by a complex web of national and regional data protection laws and growing concern about control over sensitive intellectual property.&quot;</p><p>GitLab is also cloud-neutral and model-neutral while supporting self-hosted deployments, not commercially tied to any single cloud provider or large language model (LLM). That i<a href="https://about.gitlab.com/blog/why-enterprise-independence-matters-more-than-ever-in-devsecops/" rel="">ndependence matters</a> for regulated organizations evaluating vendor concentration risk. The <a href="https://handbook.gitlab.com/handbook/product/ai/continuity-plan/" rel="">AI Continuity Plan</a> documents how vendor changes are managed, including material changes to how AI vendors treat customer data, a direct response to the governance requirements under frameworks like <a href="https://handbook.gitlab.com/handbook/legal/dora/" rel="">DORA</a>.</p><h2 id="the-governance-gap-ai-teams-need-to-close">The governance gap AI teams need to close</h2><p>GitHub&#39;s policy update is a reminder that for organizations in regulated industries, understanding exactly how an AI tool handles data is a prerequisite for using it at all. That means asking vendors for clear, documented answers: Is our data used for model training? Who are your AI model subprocessors? What happens if a vendor changes its data practices? Can we deploy in a way that keeps all AI processing within our own infrastructure? What indemnification do you offer for AI-generated output?</p><p>Vendors who can answer those questions clearly, and document those answers in an auditable form, are vendors you can build on. <strong>Those who cannot will create compliance debt every time they ship a policy update.</strong> And when a vendor can change its data practices with 30 days notice, that&#39;s not a partnership built for regulated industries. That&#39;s a liability.</p><blockquote><p>Learn more about GitLab&#39;s approach to AI governance at the <a href="https://about.gitlab.com/ai-transparency-center/" rel="">GitLab AI Transparency Center</a>.</p></blockquote>]]></content>
        <author>
            <name>Allie Holland</name>
            <uri>https://about.gitlab.com/blog/authors/allie-holland/</uri>
        </author>
        <published>2026-04-20T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab 18.11: Budget guardrails for GitLab Credits]]></title>
        <id>https://about.gitlab.com/blog/gitlab-18-11-budget-guardrails-for-gitlab-credits/</id>
        <link href="https://about.gitlab.com/blog/gitlab-18-11-budget-guardrails-for-gitlab-credits/"/>
        <updated>2026-04-16T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Teams using GitLab Duo Agent Platform with on-demand GitLab Credits are shipping faster, catching bugs earlier, and automating tasks that used to take entire sprints. But as adoption grows, so does oversight from finance, procurement, and platform teams to prove that AI spending is bounded, predictable, and controllable.</p><p>One of the greatest barriers to broader AI adoption isn&#39;t skepticism about the technology. It&#39;s uncertainty about managing spend. Without budget caps, a busy month could produce unexpected expenses. Without per-user limits, a handful of power users could burn through the team&#39;s credits before the month is over. And without either, engineering leaders who want to expand their use of agentic AI for software development have to jump through more hoops for budget approval.</p><p>Since its <a href="https://about.gitlab.com/blog/gitlab-duo-agent-platform-is-generally-available/" rel="">general availability</a>, GitLab Duo Agent Platform has provided usage governance and visibility. With GitLab 18.11, we&#39;re introducing usage controls for <a href="https://about.gitlab.com/blog/introducing-gitlab-credits/" rel="">GitLab Credits</a>: spending caps and budget guardrails that give your organization even more control and transparency over how credits are consumed.</p><h2 id="managing-gitlab-credits">Managing GitLab Credits</h2><p>GitLab 18.11 adds three layers of control over GitLab Credits consumption: a subscription-level spending cap, per-user credit limits, and visibility into cap status and enforcement.</p><h3 id="subscription-level-spending-cap">Subscription-level spending cap</h3><p>Billing account managers can now set a hard monthly ceiling for on-demand GitLab Credits consumption for their entire subscription.</p><p>Here&#39;s how it works:</p><ul><li><strong>Set a cap</strong> in the <code className="">Customers Portal</code> under your subscription&#39;s GitLab Credits settings.</li><li><strong>Enforce spend limits automatically.</strong>  When on-demand usage reaches the cap, DAP access is paused for all users on that subscription until the next monthly period begins.</li><li><strong>Make adjustments as you go.</strong> Raise or disable the cap mid-month to restore access.</li></ul><p>The cap resets each monthly period and your configured limit carries forward unless you change it. Because usage data is synchronized periodically rather than in real time, a small amount of additional usage may occur after the cap is reached before enforcement takes effect. See the <a href="https://docs.gitlab.com/subscriptions/gitlab_credits/" rel="">GitLab Credits documentation</a> for details.</p><h3 id="user-level-spending-caps">User-level spending caps</h3><p>Not every user consumes credits at the same rate, and that&#39;s expected. But when one or two power users account for a disproportionate share of the pool, the rest of the team can lose access before the month is over.</p><p>Per-user credit caps prevent any single user from consuming more than their fair share:</p><ul><li><strong>Flat per-user cap.</strong> Set a uniform credit limit that applies equally to every user on the subscription through the GitLab GraphQL API. Unlike the subscription-level cap, the per-user cap applies to a user&#39;s total consumption across all credit sources.</li><li><strong>Custom per-user overrides.</strong> For organizations that need differentiated limits, you can set individual credit caps for specific users through the GraphQL API. For example, you could give your staff engineers a higher allocation while applying a standard limit to the broader team.</li><li><strong>Individual enforcement.</strong> When a user reaches their cap, they retain full access to GitLab. Only their Duo Agent Platform credit usage is paused until the next billing cycle. Everyone else keeps working uninterrupted until they hit their own limit or the subscription-level cap is reached, whichever comes first.</li></ul><h3 id="visibility-and-notifications">Visibility and notifications</h3><p>When a subscription-level cap is reached, GitLab sends an email notification to billing account managers so they can take action: raise the cap, wait for the next period, or redistribute credits.</p><p>Within GitLab, group owners (GitLab.com) and instance administrators (Self-Managed) can view which users have been blocked due to reaching their per-user cap and restore access by adjusting the cap through the GraphQL API.</p><h2 id="how-budget-guardrails-help-organizations-scale-ai-usage">How budget guardrails help organizations scale AI usage</h2><p>Guardrails are essential as organizations ramp up their AI adoption. Here&#39;s why:</p><h3 id="predictable-ai-budgets">Predictable AI budgets</h3><p>Usage controls for GitLab Duo Agent Platform turn AI into a bounded, predictable budget item using on-demand GitLab Credits. That makes it easier to deploy agents across the software development lifecycle and get sign-off from finance, justify renewals, and plan quarterly spend.</p><h3 id="governance-and-chargeback">Governance and chargeback</h3><p>Large organizations often need to align AI consumption with internal budgets, cost centers, or departmental policies. Per-user caps give platform teams a straightforward mechanism to allocate credits fairly and track consumption at the individual level. The API import options make it practical to manage caps at enterprise scale. Combined with per-user usage data from the GitLab Credits dashboard, organizations can track consumption patterns to inform their own internal chargeback or budget allocation processes.</p><h3 id="confidence-to-scale">Confidence to scale</h3><p>Many customers start GitLab Duo Agent Platform with a small pilot group. Usage controls remove risks associated with expanding that pilot across the organization. You can roll out Duo Agent Platform to hundreds or thousands of developers knowing there&#39;s a hard ceiling protecting your budget. If usage grows faster than expected, you&#39;ll hit the cap, not an unexpected invoice.</p><h2 id="addressing-the-seat-based-and-visibility-conundrum">Addressing the seat-based and visibility conundrum</h2><p>Many AI coding tools take a seat-based approach to cost management. You buy a fixed number of seats at a flat per-user price, and that&#39;s your budget. It&#39;s simple, but rigid. You pay the same whether a developer uses the tool ten times a day or never touches it. And as vendors introduce premium models and usage-based overages on top of seat pricing, the cost predictability that seat-based licensing promised starts to erode.</p><p>GitLab takes a different approach. Usage-based pricing with hard caps and a single governance dashboard. You get the flexibility of paying for what your teams actually use, with the budget predictability of enforced spending limits.</p><h2 id="real-world-usage-controls">Real-world usage controls</h2><p><strong>One example is a mid-size SaaS customer that wants to protect their monthly budget.</strong> A 200-person engineering organization sets a subscription-level cap equal to their expected on-demand usage. Their VP of Engineering can confidently tell finance that GitLab Duo Agent Platform spend will never exceed the approved amount, even as they onboard new teams. If they approach the cap mid-month, the billing account manager gets a notification and can decide whether to raise the limit or wait for the next period.</p><p><strong>At GitLab, we also work with large enterprises that want to keep usage fair across teams.</strong> A global financial services company with 2,000 developers uses per-user caps to ensure equitable access. Staff engineers working on complex refactoring projects get a higher individual allocation via API, while most developers receive a standard flat cap. No single user can exhaust the pool, and the platform team uses the per-user usage data in the GitLab Credits dashboard to track consumption patterns and inform quarterly budget planning.</p><h2 id="getting-started">Getting started</h2><p>Usage controls are available for both GitLab.com and Self-Managed customers running GitLab 18.11. Different controls are configured in different places depending on the scope and your role.</p><p><strong>Subscription-level cap</strong></p><p>Billing account managers set the subscription-level on-demand cap in the Customers Portal:</p><ol><li>Sign in to the <code className="">Customers Portal</code>.</li><li>On your subscription card, navigate to <strong>GitLab Credits</strong> settings.</li><li>Enable the monthly on-demand credits cap and enter your desired limit.</li></ol><p><strong>Flat per-user cap</strong></p><p>The flat per-user cap can be set through the GitLab GraphQL API by namespace owners (GitLab.com) or instance administrators (Self-Managed). Check the <a href="https://docs.gitlab.com/subscriptions/gitlab_credits/" rel="">GitLab Credits documentation</a> for the latest on available configuration surfaces.</p><p><strong>Custom per-user overrides</strong></p><p>For differentiated limits, namespace owners (GitLab.com) and instance administrators (Self-Managed) can set individual caps programmatically. This is useful for automation and infrastructure-as-code workflows.</p><p><strong>Monitor usage and cap status</strong></p><ul><li><strong>Customers Portal:</strong> View detailed usage and cap status.</li><li><strong>GitLab.com:</strong> Group owners can view blocked users under <strong>Settings &gt; GitLab Credits</strong>.</li><li><strong>Self-Managed:</strong> Instance administrators can view cap status and blocked users under <strong>Admin &gt; GitLab Credits</strong>.</li></ul><h2 id="gitlab-duo-agent-platform-is-ready-to-scale">GitLab Duo Agent Platform is ready to scale</h2><p>Usage controls are available now in GitLab 18.11. If you&#39;ve been waiting for the right guardrails before expanding GitLab Duo Agent Platform across your organization, this is your moment. Set your caps, roll out Duo Agent Platform to more teams, and start shipping faster!</p><blockquote><p><a href="https://docs.gitlab.com/subscriptions/gitlab_credits/" rel="">Learn more about GitLab Credits and usage controls</a>.</p></blockquote>]]></content>
        <author>
            <name>Bryan Rothwell</name>
            <uri>https://about.gitlab.com/blog/authors/bryan-rothwell/</uri>
        </author>
        <published>2026-04-16T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab 18.11 release]]></title>
        <id>https://docs.gitlab.com/releases/18/gitlab-18-11-released/</id>
        <link href="https://docs.gitlab.com/releases/18/gitlab-18-11-released/"/>
        <updated>2026-04-16T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>This release includes Agentic SAST Vulnerability Resolution, Data Analyst Foundational Agent, CI Expert Agent, and more.</p>]]></content>
        <published>2026-04-16T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Claude Opus 4.7 is now available in GitLab Duo Agent Platform]]></title>
        <id>https://about.gitlab.com/blog/claude-opus-4-7-is-now-available-in-gitlab-duo-agent-platform/</id>
        <link href="https://about.gitlab.com/blog/claude-opus-4-7-is-now-available-in-gitlab-duo-agent-platform/"/>
        <updated>2026-04-16T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>The <a href="https://docs.gitlab.com/user/duo_agent_platform/" rel="">GitLab Duo Agent Platform</a> now supports <a href="https://www.anthropic.com/news/claude-opus-4-7" rel="">Claude Opus 4.7</a>, Anthropic&#39;s latest model, available today via model selection in <a href="https://docs.gitlab.com/user/duo_agent_platform/context/#gitlab-duo-agentic-chat" rel="">Agentic Chat</a> and across agent-powered workflows in your GitLab instance.</p><p>For teams running agents across the full software delivery lifecycle, Opus 4.7 brings meaningful improvements to the tasks that matter most: the complex, multistep work that requires sustained reasoning, precise instruction following, and the ability to verify its own outputs before surfacing results.</p><h2 id="stronger-reasoning-across-every-agent-workflow">Stronger reasoning across every agent workflow</h2><p>The most significant gain is in how Opus 4.7 handles difficult, long-running work. GitLab&#39;s internal evaluations showed improved performance over both Sonnet 4.6 and Opus 4.6. That combination translates directly to agents that work more efficiently across CI/CD pipelines, code review, vulnerability resolution, and other multi-tool workflows where compounding errors are costly.</p><p>Teams with established agent workflows should note that Opus 4.7 interprets instructions more precisely than prior models, which means it executes more faithfully on complex, conditional tasks. For example, agents handling multistep remediation sequences complete each step as specified, giving teams more predictable, auditable outcomes.</p><h2 id="agents-keep-work-moving-from-code-to-production">Agents keep work moving from code to production</h2><p>The promise of agents embedded across every stage of the software development lifecycle is that work stops waiting on people to move it forward. Opus 4.7 helps make that promise more reliable in practice.</p><p>At the code generation and test creation stage, agents benefit from Opus 4.7&#39;s ability to verify its own outputs before surfacing results. Less back-and-forth, faster iteration, fewer interruptions that pull developers out of flow. In security and vulnerability workflows, stronger instruction adherence means agents stay on task through multistep remediation sequences, completing the work as scoped rather than requiring course corrections along the way.</p><p>In CI/CD, where pipeline failures can become team-wide blockers, Opus 4.7&#39;s long-horizon consistency matters most. Agents investigating failures, analyzing logs, and proposing fixes work through that sequence coherently, without losing context mid-run. The work gets resolved rather than escalated.</p><p>GitLab Duo Agent Platform connects these stages by design. Opus 4.7 strengthens the intelligence layer that runs across all of them, so agents coordinating across planning, development, security, and deployment have a more capable model driving decisions at every handoff.</p><h2 id="pricing-and-availability">Pricing and availability</h2><p>Claude Opus 4.7 is available now in GitLab Duo Agent Platform via <a href="https://docs.gitlab.com/administration/gitlab_duo/model_selection/" rel="">model selection</a>. For a full list of models available for Duo Agent Platform along with their respective credit consumption, please visit our <a href="https://docs.gitlab.com/subscriptions/gitlab_credits/#models" rel="">documentation</a>.</p><p>You can start a <a href="https://about.gitlab.com/gitlab-duo-agent-platform/" rel="">free trial of GitLab Duo Agent Platform</a> today. If you are already using GitLab in the free tier, <a href="https://docs.gitlab.com/subscriptions/gitlab_credits/#for-the-free-tier-on-gitlabcom" rel="">you can sign up</a> for Duo Agent Platform by following a few simple steps.</p><p>And if you are an existing subscriber to GitLab Premium or Ultimate, you can simply <a href="https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/" rel="">turn on Duo Agent Platform</a> and start using the GitLab Credits <a href="https://docs.gitlab.com/subscriptions/gitlab_credits/#included-credits" rel="">that are included</a> with your subscription.</p><p><em>This blog post contains forward-looking statements within the meaning of Section 27A of the Securities Act of 1933, as amended, and Section 21E of the Securities Exchange Act of 1934. Although we believe that the expectations reflected in these statements are reasonable, they are subject to known and unknown risks, uncertainties, assumptions and other factors that may cause actual results or outcomes to differ materially. Further information on these risks and other factors is included under the caption &quot;Risk Factors&quot; in our filings with the SEC. We do not undertake any obligation to update or revise these statements after the date of this blog post, except as required by law.</em></p>]]></content>
        <author>
            <name>Rebecca Carter</name>
            <uri>https://about.gitlab.com/blog/authors/rebecca-carter/</uri>
        </author>
        <published>2026-04-16T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab 18.11: CI Expert and Data Analyst AI agents target development gaps]]></title>
        <id>https://about.gitlab.com/blog/ci-expert-and-data-analyst-ai-agents-target-development-gaps/</id>
        <link href="https://about.gitlab.com/blog/ci-expert-and-data-analyst-ai-agents-target-development-gaps/"/>
        <updated>2026-04-16T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>AI-generated code moves faster than the systems around it can keep up with. More code means more merge requests queued, more pipelines to configure, more questions about delivery that nobody has time to answer — and most of the tooling teams rely on wasn&#39;t built for this pace.</p><p>In GitLab 18.11, two new foundational agents for Duo Agent Platform address specific gaps in the development lifecycle that AI has largely left untouched:</p><ul><li>CI Expert Agent (now in beta) focuses on the gap between writing code and getting it into a running pipeline</li><li>Data Analyst Agent (now generally available) focuses on the gap between shipping code and being able to answer basic questions about how that delivery is actually going.</li></ul><p>These are problem areas that couldn&#39;t be solved by a general-purpose assistant. A tool running outside GitLab can generate a YAML file or answer a question, but it has no awareness of how your pipelines have historically performed, where failures cluster, or what your actual MR cycle times look like. That context lives in GitLab. These agents do too.</p><h2 id="fast-ci-setup-with-ci-expert-agent">Fast CI setup with CI Expert Agent</h2><p>AI has made it easier than ever to write code. Getting that code into a running pipeline is still something most teams do days, or weeks, later — if at all. The blank-page problem isn&#39;t in the editor anymore. The blank page is now in <code className="">.gitlab-ci.yml</code>.</p><p>Developers who have never configured CI don&#39;t know what language detection looks like in YAML, what their test commands should be, or how to validate the result before pushing. Teams either copy a config from a previous project that may not fit, stitch together examples from documentation, or wait for the one person who&#39;s done it before. If that person isn&#39;t available, CI becomes the thing you&#39;ll &quot;get to later.&quot; Later becomes never.</p><p>When CI never happens, the impact shows up everywhere else. Changes ship without a reliable safety net, regressions surface in production instead of in pipelines, and work piles up in bigger, riskier batches because no one wants to be the person who “breaks the build.” Over time, teams normalize working in the dark, often relying on undocumented institutional knowledge and ad-hoc testing, instead of having a fast, predictable feedback loop baked into every change.</p><p>CI Expert Agent, now available in beta, removes that friction. It inspects your repository, identifies your language and framework, and proposes a working build and test pipeline tailored to what&#39;s actually there — then explains every decision in plain language. The target: a running pipeline in minutes, with no YAML written by hand.</p><p>What CI Expert Agent does:</p><ul><li>Repo-aware pipeline generation detects language, framework, and test setup</li><li>Generates valid, runnable build and test configurations</li><li>Guided first-pipeline flow with plain-language explanation of each step in Agentic Chat</li><li>Native GitLab CI semantics with no config translation required</li></ul><p>Because it runs inside GitLab and sees real pipeline behavior over time, each improvement can build on how teams actually work, not just on static examples.</p><iframe src="https://player.vimeo.com/video/1183458036?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerPolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="CI/CD Expert Agent"></iframe><script src="https://player.vimeo.com/api/player.js"></script><br /><br /><p>CI Expert Agent is available on GitLab.com, Self-Managed, Dedicated; Free, Premium, Ultimate Editions with Duo Agent Platform enabled.</p><h2 id="query-gitlab-data-in-plain-language-with-data-analyst-agent">Query GitLab data in plain language with Data Analyst Agent</h2><p>AI has sped up how teams ship. Answering basic questions about how that work is going has gotten harder, not easier.</p><p>How long are MRs sitting in review? Which pipelines are slowing teams down? Are deployment targets actually being hit? These questions used to be answerable by glancing at a dashboard. Now, with more code, more teams, and more complexity, the data exists — it&#39;s in GitLab — but accessing it still means waiting on an analytics team, filing a dashboard request, or learning GLQL.</p><p>Data Analyst Agent targets that gap. Ask a natural-language question and get an instant visualization in Agentic Chat. No query language, no dashboard request, no waiting for the answers to be assembled by someone else.</p><p>For example, the agent can answer questions about the following topics for these roles:</p><ul><li>Engineering managers: MR cycle time, throughput by project, where reviews get stuck</li><li>Developers: Contribution patterns, flaky tests blocking their MRs, pipeline speed trends</li><li>DevOps and platform engineers: Pipeline success/failure rates, runner utilization, deployment frequency</li><li>Engineering leadership: Cross-portfolio deployment frequency, project health metrics, lead time comparisons</li></ul><p>Now generally available in 18.11, the agent covers MRs, issues, projects, pipelines, and jobs — full software development lifecycle coverage, expanded from the beta scope. Because Data Analyst Agent queries what&#39;s already in GitLab, the context is always current, and there&#39;s no pipeline to maintain or third-party tool to keep synchronized. Generated GitLab Query Language queries can be copied and used anywhere GitLab Flavored Markdown is supported, with direct export to work items and dashboards on the roadmap.</p><iframe src="https://player.vimeo.com/video/1183094817?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerPolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="Data Analyst agent demo"></iframe><script src="https://player.vimeo.com/api/player.js"></script><br /><br /><p>Data Analyst Agent is available on GitLab.com, Self-Managed, Dedicated; Free, Premium and Ultimate Edition with Duo Agent Platform enabled.</p><h2 id="one-platform-connected-context">One platform, connected context</h2><p>Both agents run inside GitLab, with access to the code, pipelines, issues, and merge requests already there. That&#39;s what separates platform-native AI from a disconnected assistant: the context is always current, and it only gets more useful over time. CI Expert Agent and Data Analyst Agent represent two concrete steps toward a platform where AI doesn&#39;t just help you write code faster; it helps you understand, ship, and maintain what gets built.</p><blockquote><p><a href="https://about.gitlab.com/gitlab-duo/" rel="">Start a free trial of GitLab Duo Agent Platform</a> to experience these foundational AI agents.</p></blockquote>]]></content>
        <author>
            <name>Corinne Dent</name>
            <uri>https://about.gitlab.com/blog/authors/corinne-dent/</uri>
        </author>
        <published>2026-04-16T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab 18.11: Automate remediation with ready-to-merge AI code fixes]]></title>
        <id>https://about.gitlab.com/blog/automate-remediation-with-ready-to-merge-ai-code-fixes/</id>
        <link href="https://about.gitlab.com/blog/automate-remediation-with-ready-to-merge-ai-code-fixes/"/>
        <updated>2026-04-16T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>AI is writing code faster than any security team can review it. What used to be a manageable backlog of static application security testing (SAST) vulnerabilities is now an overwhelming list  that has become difficult to parse. Expecting developers to manually research and fix each one isn&#39;t a process, it&#39;s a bottleneck. The answer isn&#39;t more human effort. It&#39;s an autonomous pipeline. <a href="https://docs.gitlab.com/user/application_security/vulnerabilities/agentic_vulnerability_resolution/" rel="">Agentic SAST Vulnerability Resolution</a> within GitLab Duo Agent Platform is built for that exact problem.</p><p>Now generally available, Agentic SAST Vulnerability Resolution automatically generates ready-to-merge code fixes to remediate SAST vulnerabilities. With this capability:</p><ul><li>Developers stay in flow</li><li>Vulnerabilities get resolved before they reach production</li><li>AppSec teams spend less time on triage and chasing down developers to close the loop</li></ul><p>Agentic SAST Vulnerability Resolution is the future of application security. GitLab 18.11 also delivers faster SAST scanning, smarter prioritization, and tighter governance across the platform.</p><h2 id="auto-remediation-without-breaking-your-flow">Auto-remediation without breaking your flow</h2><p>When AI is generating code at scale, the math changes. A security backlog that once grew linearly now compounds with every model-assisted commit. There is no version of this problem that gets solved by asking developers to context-switch more and continue manually remediating vulnerabilities. According to <a href="https://about.gitlab.com/resources/developer-survey/" rel="">GitLab&#39;s 2025 DevSecOps Report,</a> developers already spend 11 hours per month remediating vulnerabilities post-release — that is, fixing issues that are already exploitable in production instead of shipping new work.</p><p>Agentic SAST Vulnerability Resolution changes the economics of that cycle. When a SAST scan completes, findings automatically kick off the <a href="https://docs.gitlab.com/user/application_security/vulnerabilities/false_positive_detection/" rel="">SAST false positive detection</a> flow. Confirmed true positives go directly into the Agentic SAST Vulnerability Resolution Flow, where GitLab Duo Agent Platform:</p><ul><li>Analyzes the vulnerability in context</li><li>Generates a fix that addresses the root cause</li><li>Validates the fix through automated testing</li></ul><p>The developer receives a ready-to-merge MR with a confidence score so they can make an informed decision on how to remediate the vulnerability. The sprint stays on track, developers stay in flow, and vulnerabilities get resolved before they ever reach production.</p><p>Accelerating software production also means not waiting on your scanner. GitLab 18.11 introduces <a href="https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast/#incremental-scanning" rel="">incremental scanning for Advanced SAST</a>, so developers get vulnerability results without waiting for a full scan to complete, and pipelines keep moving.</p><iframe src="https://player.vimeo.com/video/1183195999?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479%2Fembed" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen frameBorder="0" style="position:absolute;top:0;left:0;width:100%;height:100%;"></iframe><h2 id="remediate-by-business-risk-not-just-by-score">Remediate by business risk, not just by score</h2><p>Autonomous remediation only works if the signal driving it is trustworthy. When severity scores don&#39;t reflect real exploitability, developers stop trusting the signal and start ignoring it.</p><p>GitLab 18.11 addresses this issue on four levels. First, <a href="https://docs.gitlab.com/user/application_security/vulnerabilities/severities/#critical-severity" rel="">vulnerability scores</a> are now grounded in Common Vulnerability Scoring System (CVSS) 4.0, the most current industry standard, with more granular metrics that better capture real-world exploitability. The score developers see in GitLab reflects the most current industry standard for measuring real-world risk.</p><p>From there, AppSec teams can define <a href="https://docs.gitlab.com/user/application_security/policies/vulnerability_management_policy/#severity-override-policies" rel="">policy-based rules</a> that automatically adjust vulnerability severity scores based on signals like Common Vulnerabilities and Exposures (CVE), Common Weakness Enumeration (CWE), and file path/directory. Once a policy is set, the severity overrides apply immediately so developers work from a backlog that reflects actual business risk, not raw scanner output.</p><p>Risk-based enforcement doesn&#39;t stop at the backlog. AppSec teams can now configure <a href="https://docs.gitlab.com/user/application_security/policies/merge_request_approval_policies/#vulnerability_attributes-object" rel="">approval policies to block</a> or warn based on Known Exploited Vulnerabilities (KEV) status or Exploit Prediction Scoring System (EPSS) score thresholds. When a merge gets blocked, developers know it&#39;s because the vulnerability has real-world exploitability data behind it, not a score that didn&#39;t account for their environment.</p><p>Lastly, the <a href="https://docs.gitlab.com/user/application_security/security_dashboard/#top-10-cwes" rel="">new Top CWEs security dashboard chart</a> gives teams visibility into which vulnerability classes are appearing most frequently across their projects. Instead of chasing individual findings, teams can identify patterns, prioritize at the root cause-level, and address systemic risk before it compounds.</p><h2 id="stronger-security-controls-with-less-operational-overhead">Stronger security controls with less operational overhead</h2><p>An autonomous remediation pipeline is only as good as the security scanner coverage underneath it. If the scanner enablement is inconsistent, the findings flowing into the pipeline are incomplete and so are the fixes.</p><p>GitLab 18.11 introduces <a href="https://docs.gitlab.com/user/permissions/#default-roles" rel="">Security Manager</a>, a new default role built specifically for security professionals. With the Security Manager role, security teams can enforce security scanners, define and configure security policies, manage vulnerability triage and remediation workflows, and maintain compliance frameworks and audit streams, without needing code modification or deployment permissions. Security teams get the access necessary for their jobs, and no more, keeping permissions scoped to the work at hand and keeping code and deployment permissions with developers.</p><p>For AppSec teams, getting consistent SAST scanner coverage across multiple projects and groups just got significantly easier. <a href="https://docs.gitlab.com/user/application_security/configuration/security_configuration_profiles/" rel="">SAST configuration profiles</a> give security teams a single place to define scanning once and apply it across every project in a group in one action. Teams no longer have to write and maintain YAML policy files, depend on developers to configure scanners, or manually check each project to find coverage gaps.</p><h2 id="get-started-with-agentic-vulnerability-remediation-today">Get started with agentic vulnerability remediation today</h2><p>GitLab 18.11 delivers the full vulnerability workflow in one platform: AI that automatically remediates vulnerabilities, smarter prioritization that cuts through vulnerability noise, and governance controls that give security teams the right access and coverage at scale.</p><blockquote><p>To see how GitLab Duo Agent Platform puts automated remediation directly in your developer workflow, <a href="https://about.gitlab.com/free-trial/?utm_medium=blog&amp;utm_source=blog&amp;utm_campaign=eg_global_x_inbound-request_security_en_" rel="">start a free trial of GitLab Ultimate today</a>.</p></blockquote>]]></content>
        <author>
            <name>Alisa Ho</name>
            <uri>https://about.gitlab.com/blog/authors/alisa-ho/</uri>
        </author>
        <published>2026-04-16T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[A guide to the breaking changes in GitLab 19.0]]></title>
        <id>https://about.gitlab.com/blog/a-guide-to-the-breaking-changes-in-gitlab-19-0/</id>
        <link href="https://about.gitlab.com/blog/a-guide-to-the-breaking-changes-in-gitlab-19-0/"/>
        <updated>2026-04-15T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>GitLab 17.0 shipped with 80 breaking changes. GitLab 18.0 had 27. The upcoming GitLab 19.0 release is projected to include 15.</p><p>We know that managing breaking changes across a major upgrade is time-consuming: It requires investigation and coordination across your organization. In response, we introduced a <a href="https://docs.gitlab.com/development/deprecation_guidelines/#how-do-i-get-approval-to-move-forward-with-a-breaking-change" rel="">breaking change approval requirement</a> that mandates impact mitigation and leadership sign-off before any breaking change can proceed. That process is working, and we&#39;re committed to continuing to drive that number down.</p><p>Below you&#39;ll find every breaking change in GitLab 19.0, organized by deployment type and impact, alongside the mitigation steps you need to upgrade with confidence.</p><h2 id="deployment-windows">Deployment windows</h2><p>Here are the deployment windows you need to know.</p><h3 id="gitlabcom">GitLab.com</h3><p>Breaking changes for GitLab.com will be limited to these two windows:</p><ul><li><strong>May 4–6, 2026</strong> (09:00–22:00 UTC) — primary window</li><li><strong>May 11–13, 2026</strong> (09:00–22:00 UTC) — contingency fallback</li></ul><p>Many other changes will continue to roll out throughout the month. You can learn more about the breaking changes occurring within each of these windows in the <a href="https://docs.gitlab.com/update/breaking_windows/" rel="">breaking changes documentation</a>.</p><p><strong>Note:</strong> Breaking changes may fall slightly outside of these windows in exceptional circumstances.</p><h3 id="gitlab-self-managed">GitLab Self-Managed</h3><p>GitLab 19.0 will be available starting on May 21, 2026.</p><blockquote><p>Learn more about the <a href="https://about.gitlab.com/releases/" rel="">release schedule</a>.</p></blockquote><h3 id="gitlab-dedicated">GitLab Dedicated</h3><p>The upgrade to GitLab 19.0 will take place during your assigned maintenance window. You can learn more and find your assigned maintenance window in your Switchboard portal. GitLab Dedicated instances are kept on release N-1, so the upgrade to GitLab 19.0 will take place in the maintenance window during the week of June 22, 2026.</p><p>Visit the <a href="https://docs.gitlab.com/update/deprecations/?removal_milestone=19.0&amp;breaking_only=true" rel="">Deprecations page</a> to see a full list of items scheduled for removal in GitLab 19.0. Read on to learn what&#39;s coming and how to prepare for this year&#39;s release based on your specific deployment.</p><h2 id="breaking-changes">Breaking changes</h2><p>Here are the breaking changes that are high impact.</p><h3 id="high-impact">High impact</h3><p><strong>1. Support for NGINX Ingress replaced by Gateway API with Envoy Gateway</strong></p><p><em>GitLab Self-Managed (Helm chart)</em></p><p>The GitLab Helm chart has bundled NGINX Ingress as the default networking component. NGINX Ingress reached end-of-life in March 2026, and GitLab is now transitioning to Gateway API with Envoy Gateway as the new default.</p><p>Starting with GitLab 19.0, Gateway API and the bundled Envoy Gateway become the default networking configuration. If migration to Envoy Gateway is not immediately feasible for your deployment, you can explicitly re-enable the bundled NGINX Ingress, which remains available until its planned removal in GitLab 20.0.</p><p>This change does not impact:</p><ul><li>The NGINX used in the Linux package</li><li>GitLab Helm chart and GitLab Operator instances that use an externally managed Ingress or Gateway API controller</li></ul><p>GitLab will provide best-effort security maintenance for the forked NGINX Ingress chart and builds until full removal. To ensure a smooth transition, plan your migration to the provided Gateway API solution or an externally managed Ingress controller ahead of the 19.0 upgrade.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/590800" rel="">Deprecation notice</a></p><p><strong>2. Removal of bundled PostgreSQL, Redis, and MinIO from the GitLab Helm chart</strong></p><p><em>GitLab Self-Managed (Helm chart)</em></p><p>The GitLab Helm chart has long bundled Bitnami PostgreSQL, Bitnami Redis, and a fork of the official MinIO chart to make setting up GitLab easier in proof-of-concept and test environments. Due to changes in licensing, project maintenance, and public image availability, these components will be removed from the GitLab Helm chart and GitLab Operator with no replacement.</p><p>These charts are explicitly documented as not recommended for production usage. Their sole purpose was to enable quick-start test environments.</p><p>If you are running an instance with the bundled PostgreSQL, Redis, or MinIO, follow the <a href="https://docs.gitlab.com/charts/installation/migration/bundled_chart_migration/" rel="">migration guide</a> to configure external services before upgrading to GitLab 19.0. The Redis and PostgreSQL provided by the Linux package are not impacted by this change.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/590797" rel="">Deprecation notice</a></p><p><strong>3. Resource Owner Password Credentials (ROPC) OAuth grant removed</strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>Support for the Resource Owner Password Credentials (ROPC) grant as an OAuth flow will be fully removed in GitLab 19.0. This aligns with the OAuth RFC Version 2.1 standard, which removes ROPC due to its inherent security limitations.</p><p>GitLab has already required client authentication for ROPC on GitLab.com since April 8, 2025. An administrator setting was added in 18.0 to allow controlled opt-out ahead of the removal.</p><p>After the 19.0 upgrade, ROPC cannot be used under any circumstances, even with client credentials. Any applications or integrations using this grant type must migrate to a supported OAuth flow — such as the Authorization Code flow — before upgrading.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/issues/457353" rel="">Deprecation notice</a></p><p><strong>4. PostgreSQL 16 no longer supported — PostgreSQL 17 is the new minimum</strong></p><p><em>GitLab Self-Managed</em></p><p>GitLab follows an <a href="https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/data-access/database-framework/postgresql-upgrade-cadence/" rel="">annual upgrade cadence for PostgreSQL</a>. In GitLab 19.0, PostgreSQL 17 becomes the minimum required version, and support for PostgreSQL 16 is removed.</p><p>PostgreSQL 17 is available as of GitLab 18.9, so you can upgrade at any time before the 19.0 release.</p><p>For instances running a single PostgreSQL instance installed via the Linux package, an automatic upgrade to PostgreSQL 17 may be attempted during the 18.11 upgrade. Ensure you have sufficient disk space to accommodate the upgrade.</p><p>For instances using PostgreSQL Cluster, or those that opt out of the automated upgrade, a manual upgrade to PostgreSQL 17 is required before upgrading to GitLab 19.0.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/issues/589774" rel="">Deprecation notice</a> | <a href="https://docs.gitlab.com/omnibus/settings/database/#upgrade-packaged-postgresql-server" rel="">Upgrade guide</a></p><h3 id="medium-impact">Medium impact</h3><p>Here are the breaking changes that are medium impact.</p><p><strong>1. Linux package support for Ubuntu 20.04 discontinued</strong></p><p><em>GitLab Self-Managed</em></p><p>Ubuntu standard support for Ubuntu 20.04 ended in May 2025. In accordance with GitLab&#39;s <a href="https://docs.gitlab.com/install/package/#supported-platforms" rel="">Linux package supported platforms policy</a>, packages are dropped once a vendor stops supporting the operating system.</p><p>From GitLab 19.0, packages will no longer be provided for Ubuntu 20.04. GitLab 18.11 will be the last release with Linux packages for this distribution.</p><p>If you currently run GitLab on Ubuntu 20.04, you must upgrade to Ubuntu 22.04 or another <a href="https://docs.gitlab.com/install/package/#supported-platforms" rel="">supported operating system</a> before upgrading to GitLab 19.0. Canonical provides an <a href="https://documentation.ubuntu.com/server/how-to/software/upgrade-your-release/" rel="">upgrade guide</a> to help with the migration.</p><p><a href="https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/8915" rel="">Deprecation notice</a></p><p><strong>2. Support for Redis 6 removed</strong></p><p><em>GitLab Self-Managed</em></p><p>In GitLab 19.0, support for Redis 6 is removed. Before upgrading, instances using an external Redis 6 deployment must migrate to either Redis 7.2 or Valkey 7.2, which is available in beta from GitLab 18.9 with general availability planned for GitLab 19.0.</p><p>The bundled Redis included with the Linux package has used Redis 7 since GitLab 16.2 and is not affected. Only instances using an external Redis 6 deployment must act.</p><p>Migration resources are available for common platforms:</p><ul><li><strong>AWS ElastiCache:</strong> Upgrade to <a href="https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/supported-engine-versions.html" rel="">Redis 7.2 or Valkey 7.2</a></li><li><strong>GCP Memorystore:</strong> Upgrade to <a href="https://cloud.google.com/memorystore/docs/redis/supported-versions" rel="">Redis 7.2 or Valkey 7.2</a></li><li><strong>Azure Cache for Redis:</strong> Managed Redis 7.2 or Valkey 7.2 is not yet available on Azure. You can self-host on Azure VMs or AKS, or use the Linux package installation, which will support Valkey 7.2 with GitLab 19.0 GA.</li><li><strong>Self-hosted:</strong> Upgrade your Redis 6 instance to Redis 7.2 or Valkey 7.2.</li></ul><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/585839" rel="">Deprecation notice</a> | <a href="https://docs.gitlab.com/install/requirements/" rel="">Requirements documentation</a></p><p><strong>3. <code className="">heroku/builder:22</code> image replaced by <code className="">heroku/builder:24</code></strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>The cloud-native buildpack (CNB) builder image used in Auto DevOps has been updated to <code className="">heroku/builder:24</code>. This affects pipelines that use the <a href="https://gitlab.com/gitlab-org/cluster-integration/auto-build-image" rel=""><code className="">auto-build-image</code></a> provided by the <a href="https://docs.gitlab.com/topics/autodevops/stages/#auto-build" rel="">Auto Build stage of Auto DevOps</a>.</p><p>While most workloads will be unaffected, this may be a breaking change for some users. Before upgrading, review the <a href="https://devcenter.heroku.com/articles/heroku-24-stack#what-s-new" rel="">Heroku-24 stack release notes</a> and <a href="https://devcenter.heroku.com/articles/heroku-24-stack#upgrade-notes" rel="">upgrade notes</a> to assess your impact.</p><p>If you need to continue using <code className="">heroku/builder:22</code> after GitLab 19.0, set the CI/CD variable <code className="">AUTO_DEVOPS_BUILD_IMAGE_CNB_BUILDER</code> to <code className="">heroku/builder:22</code>.</p><p><a href="https://gitlab.com/gitlab-org/cluster-integration/auto-build-image/-/issues/79" rel="">Deprecation notice</a></p><p><strong>4. Mattermost removed from the Linux package</strong></p><p><em>GitLab Self-Managed</em></p><p>In GitLab 19.0, bundled Mattermost is removed from the Linux package. Mattermost was first bundled with GitLab in 2015, but has since matured its own standalone deployment options. Additionally, with Mattermost v11, <a href="https://forum.mattermost.com/t/mattermost-v11-changes-in-free-offerings/25126" rel="">GitLab SSO was deprecated from their free offering</a>, reducing the value of the bundled integration.</p><p>Customers not using the bundled Mattermost will not be impacted. If you currently use it, refer to <a href="https://docs.mattermost.com/administration-guide/onboard/migrate-gitlab-omnibus.html" rel="">Migrating from GitLab Omnibus to Mattermost Standalone</a> in the Mattermost documentation for migration instructions.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/590798" rel="">Deprecation notice</a></p><p><strong>5. Linux package support for SUSE distributions discontinued</strong></p><p><em>GitLab Self-Managed</em></p><p>In GitLab 19.0, Linux package support for SUSE distributions ends. This affects:</p><ul><li>openSUSE Leap 15.6</li><li>SUSE Linux Enterprise Server 12.5</li><li>SUSE Linux Enterprise Server 15.6</li></ul><p>GitLab 18.11 will be the last version with Linux packages for these distributions. The recommended path forward is to migrate to a <a href="https://docs.gitlab.com/install/docker/installation/" rel="">Docker deployment of GitLab</a> on your existing distribution, avoiding the need to change your underlying operating system to continue receiving upgrades.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/590801" rel="">Deprecation notice</a></p><h3 id="low-impact">Low impact</h3><p>Here are the breaking changes that are low impact.</p><p><strong>1. Spamcheck removed from Linux package and GitLab Helm chart</strong></p><p><em>GitLab Self-Managed</em></p><p>In GitLab 19.0, <a href="https://docs.gitlab.com/administration/reporting/spamcheck/" rel="">Spamcheck</a> is removed from the Linux package and GitLab Helm chart. It is primarily relevant to large public instances, which is an edge case in GitLab&#39;s customer base. The removal reduces package size and dependency footprint for the majority of customers.</p><p>Customers not currently using Spamcheck will not be impacted. If you currently use the bundled Spamcheck, you can deploy it separately using <a href="https://gitlab.com/gitlab-org/gl-security/security-engineering/security-automation/spam/spamcheck" rel="">Docker</a>. No data migration is required.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/590796" rel="">Deprecation notice</a></p><p><strong>2. Slack slash commands integration removed</strong></p><p><em>GitLab Self-Managed | Dedicated</em></p><p>The <a href="https://docs.gitlab.com/user/project/integrations/slack_slash_commands/" rel="">Slack slash commands integration</a> is deprecated in favor of the <a href="https://docs.gitlab.com/user/project/integrations/gitlab_slack_application/" rel="">GitLab for Slack app</a>, which provides a more secure integration with the same capabilities.</p><p>From GitLab 19.0, users will no longer be able to configure or use Slack slash commands. This integration only exists on GitLab Self-Managed and GitLab Dedicated — GitLab.com users are not affected.</p><p>To check if your instance is impacted, see the <a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/569345#am-i-impacted" rel="">impact check guidance</a>.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/569345" rel="">Deprecation notice</a></p><p><strong>3. Bitbucket Cloud import via API no longer supports app passwords</strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>Atlassian has deprecated app passwords (username and password authentication) for Bitbucket Cloud and has announced that this authentication method will stop working on June 9, 2026.</p><p>From GitLab 19.0, importing repositories from Bitbucket Cloud through the GitLab API requires <a href="https://support.atlassian.com/organization-administration/docs/understand-user-api-tokens/" rel="">user API tokens</a> instead of app passwords. Users importing from Bitbucket Server, or from Bitbucket Cloud through the GitLab UI, are not affected.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/588961" rel="">Deprecation notice</a> | <a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/588961#am-i-impacted" rel="">Impact check</a></p><p><strong>4. Trending tab removed from Explore projects page</strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>The <strong>Trending</strong> tab in <strong>Explore &gt; Projects</strong> and its associated GraphQL arguments are removed in GitLab 19.0. The trending algorithm only considers public projects, making it ineffective for Self-Managed instances that primarily use internal or private project visibility.</p><p>In the month before the GitLab 19.0 release, the <strong>Trending</strong> tab on GitLab.com will redirect to the <strong>Active</strong> tab sorted by stars in descending order.</p><p>Also removed: the <code className="">trending</code> argument in the <code className="">Query.adminProjects</code>, <code className="">Query.projects</code>, and <code className="">Organization.projects</code> GraphQL types.</p><p><a href="https://gitlab.com/groups/gitlab-org/-/work_items/18493" rel="">Deprecation notice</a></p><p><strong>5. Container registry storage driver updates</strong></p><p><em>GitLab Self-Managed</em></p><p>Two legacy container registry storage drivers are being replaced in GitLab 19.0:</p><ul><li><strong>Azure storage driver:</strong> The legacy <code className="">azure</code> driver becomes an alias for the new <code className="">azure_v2</code> driver. No manual action is required, but proactive migration is recommended for improved reliability and performance. See the <a href="https://docs.gitlab.com/administration/packages/container_registry/#use-object-storage" rel="">object storage documentation</a> for migration steps. <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/523096" rel="">Deprecation notice</a></li><li><strong>S3 storage driver (AWS SDK v1):</strong> The legacy <code className="">s3</code> driver becomes an alias for the new <code className="">s3_v2</code> driver. The <code className="">s3_v2</code> driver does not support Signature Version 2 — any <code className="">v4auth: false</code> configuration will be transparently ignored. Migrate to Signature Version 4 before upgrading. <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/523095" rel="">Deprecation notice</a></li></ul><p><strong>6. <code className="">ciJobTokenScopeAddProject</code> GraphQL mutation removed</strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>The <code className="">ciJobTokenScopeAddProject</code> GraphQL mutation is deprecated in favor of <code className="">ciJobTokenScopeAddGroupOrProject</code>, introduced alongside the CI/CD job token scope changes in GitLab 18.0. Update any automation or tooling using the deprecated mutation before upgrading.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/issues/474175" rel="">Deprecation notice</a></p><p><strong>7. <code className="">ci_job_token_scope_enabled</code> projects API attribute removed</strong></p><p><em>GitLab.com | Self-Managed | Dedicated</em></p><p>The <code className="">ci_job_token_scope_enabled</code> attribute in the <a href="https://docs.gitlab.com/api/projects/" rel="">Projects REST API</a> is removed in GitLab 19.0. This attribute was deprecated in GitLab 18.0 when the underlying setting was removed, and has since always returned <code className="">false</code>.</p><p>To control CI/CD job token access, use the <a href="https://docs.gitlab.com/ci/jobs/ci_job_token/#control-job-token-access-to-your-project" rel="">CI/CD job token project settings</a>.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/issues/423091" rel="">Deprecation notice</a></p><p><strong>8. Unauthenticated Projects API pagination limit enforced on GitLab.com</strong></p><p><em>GitLab.com</em></p><p>To maintain platform stability and ensure consistent performance, a maximum offset limit of 50,000 will be enforced for all unauthenticated requests to the Projects List REST API on GitLab.com. For example, the <code className="">page</code> parameter will be limited to 2,500 pages when retrieving 20 results per page.</p><p>Workflows requiring access to more data must use keyset-based pagination parameters. This limit applies only to GitLab.com. On GitLab Self-Managed and GitLab Dedicated, the offset limit will be disabled by default behind a feature flag.</p><p><a href="https://gitlab.com/gitlab-org/gitlab/-/work_items/585176" rel="">Deprecation notice</a></p><h2 id="resources-to-manage-your-impact">Resources to manage your impact</h2><p>We&#39;ve developed specific tooling to help customers understand how these planned changes impact their GitLab instance(s). Once you&#39;ve assessed your impact, we recommend reviewing the mitigation steps provided in the documentation relevant to each change to ensure a smooth transition to GitLab 19.0.</p><p><strong><a href="https://gitlab.com/gitlab-com/support/toolbox/gitlab-detective" rel="">GitLab Detective</a> (Self-Managed only):</strong> This experimental tool automatically checks a GitLab installation for known issues by looking at config files and database values. Note: it must run directly on your GitLab nodes.</p><p>If you have a paid plan and have questions or require assistance with these changes, please open a support ticket on the <a href="https://support.gitlab.com/" rel="">GitLab Support Portal</a>.</p><p>If you are a free GitLab.com user, you can access additional support through community sources such as <a href="https://docs.gitlab.com/" rel="">GitLab Documentation</a>, the <a href="https://forum.gitlab.com/" rel="">GitLab Community Forum</a>, and <a href="https://stackoverflow.com/questions/tagged/gitlab" rel="">Stack Overflow</a>.</p>]]></content>
        <author>
            <name>Martin Brümmer</name>
            <uri>https://about.gitlab.com/blog/authors/martin-brmmer/</uri>
        </author>
        <published>2026-04-15T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab and Vertex AI on Google Cloud: Advancing agentic software development]]></title>
        <id>https://about.gitlab.com/blog/gitlab-and-vertex-ai-on-google-cloud/</id>
        <link href="https://about.gitlab.com/blog/gitlab-and-vertex-ai-on-google-cloud/"/>
        <updated>2026-04-14T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>GitLab Duo Agent Platform is helping redefine how organizations build, secure, and deliver software. Since its general availability in January 2026, the platform is bringing agentic AI to every phase of the software development lifecycle. Duo Agent Platform is an intelligent orchestration layer where software teams, and their specialized agents plan, code, review, and remediate security vulnerabilities together.</p><p>Through this exciting partnership, <a href="https://about.gitlab.com/gitlab-duo-agent-platform/" rel="">GitLab Duo Agent Platform</a> automates software development orchestration and lifecycle context via its integration with Vertex AI on Google Cloud, which powers the model tier for agent calls. Software teams keep working on issues, merge requests, pipelines, and security workflows while inference follows the Google Cloud posture they already defined.</p><p>Advances in Google Cloud’s Vertex AI models expand how Google Cloud customers can use GitLab Duo Agent Platform in their environment. Customers get an AI-powered DevSecOps control plane in GitLab, backed by a rapidly advancing AI infrastructure foundation in Vertex AI and Duo Agent Platform’s flexible deployment and integration options. The combination enables more capable, governed agentic workflows that operate at enterprise scale.</p><p><img alt="Conceptual illustration of the GitLab Duo Agent Platform integrated with Google Cloud&#39;s Vertex AI to power agentic software development and governed AI workflows" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1776165990/b7jlux9kydafncwy8spc.png" /></p><h2 id="agents-that-work-across-the-full-lifecycle">Agents that work across the full lifecycle</h2><p>Many AI tools focus on a single task: generating code faster. GitLab Duo Agent Platform goes further. It orchestrates AI agents across the entire software development lifecycle (SDLC), from planning through security review to delivery, across many teams with many projects and releases. At this scale, AI coding assistants are necessary for continuous innovation but not sufficient.</p><p>Single-purpose coding assistants rarely see the full state of a project. Backlog shape, open merge requests, failing jobs, and security findings live in GitLab, but a separate chat window in a coding assistant does not inherit that full picture of the SDLC. The gap shows up as manual handoffs, duplicate explanations to an AI that lacks context, and governance teams trying to map data flows across tools that were never designed as one system.</p><p>GitLab Duo Agent Platform helps close that gap by running agents and flows on the same objects engineers use every day. Vertex AI then supplies the models and services those agents call when Google Cloud is your chosen inference home, with GitLab’s AI Gateway mediating access so administrators keep a clear map of what connects to what. For instance, GitLab Duo Planner Agent analyzes backlogs, breaks epics into structured tasks, and applies prioritization frameworks to help teams decide what to build next. Security Analyst Agent triages vulnerabilities, details risks in plain language, and recommends remediation in priority order. Built-in flows connect these agents into end-to-end processes, without requiring developers to manage every handoff manually.</p><p>Agentic Chat in GitLab Duo Agent Platform ties the experience together for developers. They query in natural language to get context-aware responses with multi-step reasoning that draws on the full state of a project: its issues, merge requests, pipelines, security findings, and codebase. Because GitLab serves as the system of record for the SDLC with a unified data model, GitLab Duo agents operate with lifecycle context that falls outside the reach of standalone, tool-specific AI assistants.</p><h3 id="amplified-by-vertex-ai">Amplified by Vertex AI</h3><p>GitLab Duo Agent Platform is designed to be model-flexible, routing different capabilities to different models based on what performs best for a given task. That architectural choice pays off on Google Cloud, where Vertex AI acts as the managed environment for foundation models and related services, providing a broad model ecosystem and managed infrastructure that helps push the platform&#39;s capabilities further.</p><p>The latest generations of AI models available through Vertex AI bring significant improvements in reasoning, tool use, and long-context understanding compared to previous iterations — the same properties that GitLab&#39;s agents rely on across many projects and teams with large, complex codebases. Longer context windows and richer tool integration in the underlying models expand what agents can accomplish in a single pass, which is especially important for workloads like deep backlog analysis or monorepo security review.</p><p><a href="https://cloud.google.com/model-garden" rel="">Vertex AI Model Garden</a>, with access to a wide range of foundation models, gives customers the breadth to make these choices based on performance, cost, and regulatory requirements rather than vendor lock-in.</p><p>Moreover, GitLab customers can use Bring Your Own Model (BYOM) for Duo Agent Platform so approved providers and gateways land where your security model expects them. GitLab’s <a href="https://about.gitlab.com/blog/agentic-ai-enterprise-control-self-hosted-duo-agent-platform-and-byom/" rel="">18.9 launch coverage of self-hosted Duo Agent Platform and BYOM</a> describes how that wiring works. With this deployment option, customers gain access to a wider set of model options they can tailor to their software development process: the right model for the right workflow, with the right guardrails.</p><p>For GitLab, the decision to build on Vertex AI was driven by the need for enterprise-grade reliability and unparalleled model breadth. Vertex AI and Model Garden completely abstract the heavy lifting of LLM hosting — meaning rapid version delivery, robust security, and strict governance are seamlessly built into the integration. Beyond offering Gemini models, Vertex AI provides global, low-latency access to a vast catalog of third-party and open-source models.</p><p>Combined with Google Cloud&#39;s industry-leading approach to data privacy and model protection, Vertex AI emerged as the clear choice to power GitLab&#39;s next-generation developer experience.</p><p>By integrating Vertex AI Model Garden into its backend, GitLab supercharges its DevSecOps platform without passing any complexity on to users. Development teams are not burdened with evaluating or managing underlying LLMs; instead, they experience a streamlined, AI-assisted workflow for building their applications.</p><p>GitLab completely abstracts cloud orchestration, enabling developers to focus entirely on writing great code, while Vertex AI powers the features and functionality that assist them.</p><h2 id="what-this-means-for-customers-on-google-cloud">What this means for customers on Google Cloud</h2><p>GitLab Duo Agent Platform already delivers AI agents that operate across the full software lifecycle within a single, governed system of record. On Google Cloud, it enables rapid innovation as Vertex AI continues to advance the model and infrastructure layers.</p><p>For Google Cloud customers, this integration means streamlined software delivery while maintaining strict enterprise governance. For platform engineering groups, it means normalizing which Vertex-backed models power suggestions, analysis, and remediation inside GitLab instead of cataloging dozens of client-side tools. Security programs benefit when agents propose and validate fixes in the same place developers already triage findings, cutting context switching and reducing work that would otherwise spill into unmanaged channels.</p><p>From a cloud economics and policy angle, drawing agent inference toward Vertex from within GitLab keeps usage nearer to the agreements and controls you already run on Google Cloud, which helps avoid duplicate spend and shadow paths that bypass procurement.</p><p>Because Vertex AI is an underlying infrastructure provider for GitLab Duo Agent Platform, organizations are enabled to dramatically lift developer productivity without the overhead and risk of managing fragmented AI toolchains. Teams stay aligned within a single, secure system of record, helping them build applications faster and ship with confidence.</p><p>The GitLab and Google Cloud collaboration has been building since 2018. Today, it represents one of the most comprehensive paths for organizations moving from AI experiments to fully governed, agentic software development on Google Cloud. As both platforms continue to advance — GitLab expanding its agent orchestration and developer context, and Vertex AI pushing the boundaries of model capability and agent infrastructure — the value for joint customers will continue to grow.</p><blockquote><p><a href="https://about.gitlab.com/free-trial/" rel="">Start a free trial of GitLab Duo Agent Platform</a> to experience the power of GitLab and Vertex AI on Google Cloud.</p></blockquote>]]></content>
        <author>
            <name>Regnard Raquedan</name>
            <uri>https://about.gitlab.com/blog/authors/regnard-raquedan/</uri>
        </author>
        <author>
            <name>Rajesh Agadi</name>
            <uri>https://about.gitlab.com/blog/authors/rajesh-agadi/</uri>
        </author>
        <published>2026-04-14T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab named a 2026 Omdia Universe Leader]]></title>
        <id>https://about.gitlab.com/blog/gitlab-named-a-2026-omdia-universe-leader/</id>
        <link href="https://about.gitlab.com/blog/gitlab-named-a-2026-omdia-universe-leader/"/>
        <updated>2026-04-13T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>GitLab is named a Leader in the 2026 Omdia Universe for AI-assisted Software Development, IDE-based Tools. Of the nineteen vendors evaluated by the independent analyst firm, GitLab earned best-in-class scores in three categories: Solution Breadth (100%), Strategy and Innovation (88%), and Core Features (82%). Top-tier ratings followed for Extended Features and Vendor Execution.</p><p>This year&#39;s assessment is notable for a specific reason: Omdia expanded its evaluation criteria, and for the first time, AI development tools were scored on full software lifecycle capability, not just coding. That shift mirrors where the AI evolution is heading and shook up which vendors came out on top.</p><p><img alt="Omdia Universe chart" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775848262/asyd6bpbtwlhicqonhit.png" title="Source: Omdia, Universe: AI-assisted Software Development, Part 1: IDE-based Tools, 2026" /></p><blockquote><p><a href="https://learn.gitlab.com/c/analyst-omdia-ai?x=fRC1cQ" rel="">Download the full Omdia Universe report.</a></p></blockquote><h2 id="about-omdia-universe">About Omdia Universe</h2><p>Omdia Universe plots vendors across Solution Capability and Strategy and Execution, producing three tiers: Leaders (strongest on both axes, recommended for every shortlist), Challengers (narrower feature range or earlier in maturity), and Prospects (earlier-stage or adjacent-fit vendors).</p><h2 id="what-changed-in-this-years-assessment">What changed in this year&#39;s assessment</h2><p>The expansion of Omdia&#39;s criteria reflects something practitioners are already experiencing. AI coding tools have raised developer output significantly, and applications that once took weeks can now be prototyped in a fraction of the time. But acceleration at the coding stage does not automatically translate to faster delivery. Review backlogs grow. Security findings accumulate. Deployments still require coordination across teams using tools that were not designed to work together.</p><p>Omdia captured this dynamic directly: The tools pulling ahead are the ones that handle testing, security, deployment, and orchestration. Not just code generation. That finding drove the decision to broaden the assessment criteria and separated the Leaders from the Challengers.</p><p>The other major shift in this year&#39;s report is how Omdia treated agentic AI. The 2026 assessment weighted agentic capabilities as a current evaluation dimension rather than a future consideration. This includes whether a platform can coordinate multiple tasks autonomously, orchestrate handoffs between specialized agents, and support teams at different stages of agent adoption.</p><h2 id="where-gitlab-scored">Where GitLab scored</h2><p>GitLab earned best-in-class scores in three categories:</p><p><strong>Solution Breadth: 100%.</strong> Coverage of the full SDLC in a single platform, from planning and requirements through deployment and issue management. This includes lifecycle phases that most AI coding tools do not touch. For example, prebuilt agents like <a href="https://docs.gitlab.com/user/duo_agent_platform/agents/foundational_agents/planner/" rel="">Planner Agent</a> and <a href="https://docs.gitlab.com/user/duo_agent_platform/agents/foundational_agents/security_analyst_agent/" rel="">Security Analyst Agent</a> extend AI assistance into sprint planning, vulnerability triage, and remediation guidance: the parts of the lifecycle where delivery actually gets stuck.</p><p><strong>Strategy and Innovation: 88%.</strong> Differentiation through end-to-end orchestration, privacy-first architecture with no training on private data, and multi-model support via partnerships with Anthropic, Google, and AWS. Teams can select models suited to their workload and data requirements. The platform&#39;s approach to unified context, where agents collaborate across issues, merge requests, pipelines, and security findings without losing state, is an example of the architectural innovation Omdia recognized in this category.</p><p><strong>Core Features: 82%.</strong> This score reflects deep coverage across the parts of the lifecycle where engineering teams spend most of their time. Code is generated with real-time context from the IDE and codebase, tested across unit, integration, and security dimensions, and reviewed with prioritization built in. DevOps automation handles CI/CD, GitOps, and <a href="https://docs.gitlab.com/user/gitlab_duo_chat/examples/#troubleshoot-failed-cicd-jobs-with-root-cause-analysis" rel="">root cause analysis</a> for pipeline failures. The <a href="https://docs.gitlab.com/user/analytics/duo_and_sdlc_trends/" rel="">AI Impact Dashboard</a> gives teams measurable visibility into cycle times, deployment frequency, and where AI is actually moving the needle on productivity.</p><p>GitLab also earned top-tier recognition for Extended Features (80%) and Vendor Execution (88%).</p><h2 id="the-changing-role-of-human-developers-and-ai-agents">The changing role of human developers and AI agents</h2><p>One of the more substantive findings in the Omdia report concerns the evolving role of the software developer alongside these tools. Development teams are increasingly a mix of AI engineers and their AI agents, with engineers supervising and directing agentic AI. With AI coding generating the bulk of the code, the human&#39;s job shifts toward ensuring technology requirements are actually met, supervising quality, applying right guardrails, designing autonomous production pipelines, and mediating between business goals and the use of agentic AI across the software lifecycle.</p><p>This shift has implications for how organizations evaluate their AI investments. A team that has automated code generation but still handles review, testing, and deployment manually has not yet truly accelerated software innovation. The productivity gain from faster coding compounds when the rest of the lifecycle can keep pace. It shrinks when it cannot, and the bottlenecks move downstream instead.</p><h2 id="enterprise-readiness-as-table-stakes">Enterprise readiness as table stakes</h2><p>Something notable in how Omdia structured this year&#39;s assessment: enterprise controls and guardrails are no longer a bonus category. Compliance certifications, deployment flexibility, and privacy architecture appeared as baseline expectations for Leader-tier platforms, not as distinguishing features. Organizations in regulated industries and those with data sovereignty requirements are now weighing these factors as entry criteria.</p><p>GitLab&#39;s posture on these dimensions highlight its unique differentiation in the market: SOC 2 and ISO 27001 certified platform, <a href="https://about.gitlab.com/blog/why-enterprise-independence-matters-more-than-ever-in-devsecops/" rel="">privacy-first design</a> with no training on private customer data for its agentic AI capabilities, self-managed deployment support across cloud and on-premises (including air-gapped environments), and support for self-hosted AI models. Its consumption as a single-tenant SaaS application via GitLab Dedicated, with FedRAMP Moderate Authorized via GitLab Dedicated for Government, extends its leadership in deployment flexibility.</p><p>The Omdia report recognized these not as a feature list but as evidence of the platform&#39;s readiness for the organizations where the compliance bar is highest: financial services, government, healthcare, and other regulated sectors that cannot compromise on data residency or auditability.</p><h2 id="benchmark-your-maturity-in-software-development">Benchmark your maturity in software development</h2><p>For teams actively evaluating where their AI development strategy stands, Omdia&#39;s recommendation is clear: GitLab belongs on the top of the list.</p><p>The deeper question for most engineering leaders right now is not which AI tool generates the best code. It is whether the code being generated can be put to production with the highest level of quality, security, and performance. It must be understood, governed, and maintained by the software teams responsible for it. With GitLab, coding speed translates to innovation velocity.</p><p>If you want to benchmark your organization’s maturity in software development best practices and evolution, you can get a personalized score and concrete next steps to take in these assessments for <a href="https://about.gitlab.com/assessments/ai-modernization-assessment/" rel="">AI Modernization</a>, <a href="https://about.gitlab.com/assessments/devops-modernization-assessment/" rel="">DevOps Modernization</a>, and <a href="https://about.gitlab.com/assessments/security-modernization-assessment/" rel="">Security Modernization</a>.</p><p><a href="https://learn.gitlab.com/c/analyst-omdia-ai?x=fRC1cQ" rel="">Download the full Omdia Universe report.</a></p>]]></content>
        <author>
            <name>Rebecca Carter</name>
            <uri>https://about.gitlab.com/blog/authors/rebecca-carter/</uri>
        </author>
        <published>2026-04-13T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[5 ways GitLab pipeline logic solves real engineering problems]]></title>
        <id>https://about.gitlab.com/blog/5-ways-gitlab-pipeline-logic-solves-real-engineering-problems/</id>
        <link href="https://about.gitlab.com/blog/5-ways-gitlab-pipeline-logic-solves-real-engineering-problems/"/>
        <updated>2026-04-09T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Most CI/CD tools can run a build and ship a deployment. Where they diverge is what happens when your delivery needs get real: a monorepo with a dozen services, microservices spread across multiple repositories, deployments to dozens of environments, or a platform team trying to enforce standards without becoming a bottleneck.</p><p>GitLab&#39;s pipeline execution model was designed for that complexity. Parent-child pipelines, DAG execution, dynamic pipeline generation, multi-project triggers, merge request pipelines with merged results, and CI/CD Components each solve a distinct class of problems. Because they compose, understanding the full model unlocks something more than a faster pipeline. In this article, you&#39;ll learn about the five patterns where that model stands out, each mapped to a real engineering scenario with the configuration to match.</p><p>The configs below are illustrative. The scripts use echo commands to keep the signal-to-noise ratio low. Swap them out for your actual build, test, and deploy steps and they are ready to use.</p><h2 id="_1-monorepos-parent-child-pipelines-dag-execution">1. Monorepos: Parent-child pipelines + DAG execution</h2><p>The problem: Your monorepo has a frontend, a backend, and a docs site. Every commit triggers a full rebuild of everything, even when only a README changed.</p><p>GitLab solves this with two complementary features: <a href="https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#parent-child-pipelines" rel="">parent-child pipelines</a> (which let a top-level pipeline spawn isolated sub-pipelines) and <a href="https://docs.gitlab.com/ci/yaml/#needs" rel="">DAG execution via <code className="">needs</code></a> (which breaks rigid stage-by-stage ordering and lets jobs start the moment their dependencies finish).</p><p>A parent pipeline detects what changed and triggers only the relevant child pipelines:</p><pre className="language-yaml shiki shiki-themes github-light" code="# .gitlab-ci.yml
stages:
  - trigger

trigger-services:
  stage: trigger
  trigger:
    include:
      - local: &#39;.gitlab/ci/api-service.yml&#39;
      - local: &#39;.gitlab/ci/web-service.yml&#39;
      - local: &#39;.gitlab/ci/worker-service.yml&#39;
    strategy: depend
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">trigger
</span></span><span class="line" line="4"><span emptyLinePlaceholder>
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">trigger-services</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">trigger
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">    include</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">local</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;.gitlab/ci/api-service.yml&#39;
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">local</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;.gitlab/ci/web-service.yml&#39;
</span></span><span class="line" line="11"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">local</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&#39;.gitlab/ci/worker-service.yml&#39;
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">    strategy</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">depend
</span></span></code></pre><p>Each child pipeline is a fully independent pipeline with its own stages, jobs, and artifacts. The parent waits for all of them via <a href="https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#wait-for-downstream-pipeline-to-complete" rel="">strategy: depend</a> so you get a single green/red signal at the top level, with full drill-down into each service&#39;s pipeline. This organizational separation is the bigger win for large teams: each service owns its pipeline config, changes in one cannot break another, and the complexity stays manageable as the repo grows.</p><p>One thing worth knowing: when you pass <a href="https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#combine-multiple-child-pipeline-configuration-files" rel="">multiple files to a single <code className="">trigger: include:</code></a>, GitLab merges them into a single child pipeline configuration. This means jobs defined across those files share the same pipeline context and can reference each other with <code className="">needs:</code>, which is what makes the DAG optimization possible. If you split them into separate trigger jobs instead, each would be its own isolated pipeline and cross-file <code className="">needs:</code> references would not work.</p><p>Combine this with <code className="">needs:</code> inside each child pipeline and you get DAG execution. Your integration tests can start the moment the build finishes, without waiting for other jobs in the same stage.</p><pre className="language-yaml shiki shiki-themes github-light" code="# .gitlab/ci/api-service.yml
stages:
  - build
  - test

build-api:
  stage: build
  script:
    - echo &quot;Building API service&quot;

test-api:
  stage: test
  needs: [build-api]
  script:
    - echo &quot;Running API tests&quot;
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># .gitlab/ci/api-service.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="5"><span emptyLinePlaceholder>
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">build-api</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Building API service&quot;
</span></span><span class="line" line="10"><span emptyLinePlaceholder>
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">test-api</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">  needs</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">build-api</span><span style="--shiki-default:#24292E">]
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running API tests&quot;
</span></span></code></pre><p>Why it matters: Teams with large monorepos typically report significant reductions in pipeline runtime after switching to DAG execution, since jobs no longer wait on unrelated work in the same stage. Parent-child pipelines add the organizational layer that keeps the configuration maintainable as the repo and team grow.</p><p><img alt="Local downstream pipelines" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738759/Blog/Imported/hackathon-fake-blog-post-s/image3_vwj3rz.png" title="Local downstream pipelines" /></p><h2 id="_2-microservices-cross-repo-multi-project-pipelines">2. Microservices: Cross-repo, multi-project pipelines</h2><p>The problem: Your frontend lives in one repo, your backend in another. When the frontend team ships a change, they have no visibility into whether it broke the backend integration and vice versa.</p><p>GitLab&#39;s <a href="https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#multi-project-pipelines" rel="">multi-project pipelines</a> let one project trigger a pipeline in a completely separate project and wait for the result. The triggering project gets a linked downstream pipeline right in its own pipeline view.</p><p>The frontend pipeline builds an API contract artifact and publishes it, then triggers the backend pipeline. The backend fetches that artifact directly using the <a href="https://docs.gitlab.com/api/jobs/#download-a-single-artifact-file-from-specific-tag-or-branch" rel="">Jobs API</a> and validates it before allowing anything to proceed. If a breaking change is detected, the backend pipeline fails and the frontend pipeline fails with it.</p><pre className="language-yaml shiki shiki-themes github-light" code="# frontend repo: .gitlab-ci.yml
stages:
  - build
  - test
  - trigger-backend

build-frontend:
  stage: build
  script:
    - echo &quot;Building frontend and generating API contract...&quot;
    - mkdir -p dist
    - |
      echo &#39;{
        &quot;api_version&quot;: &quot;v2&quot;,
        &quot;breaking_changes&quot;: false
      }&#39; &gt; dist/api-contract.json
    - cat dist/api-contract.json
  artifacts:
    paths:
      - dist/api-contract.json
    expire_in: 1 hour

test-frontend:
  stage: test
  script:
    - echo &quot;All frontend tests passed!&quot;

trigger-backend-pipeline:
  stage: trigger-backend
  trigger:
    project: my-org/backend-service
    branch: main
    strategy: depend
  rules:
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># frontend repo: .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="5"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">trigger-backend
</span></span><span class="line" line="6"><span emptyLinePlaceholder>
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">build-frontend</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Building frontend and generating API contract...&quot;
</span></span><span class="line" line="11"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">mkdir -p dist
</span></span><span class="line" line="12"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#D73A49">|
</span></span><span class="line" line="13"><span style="--shiki-default:#032F62">      echo &#39;{
</span></span><span class="line" line="14"><span style="--shiki-default:#032F62">        &quot;api_version&quot;: &quot;v2&quot;,
</span></span><span class="line" line="15"><span style="--shiki-default:#032F62">        &quot;breaking_changes&quot;: false
</span></span><span class="line" line="16"><span style="--shiki-default:#032F62">      }&#39; &gt; dist/api-contract.json
</span></span><span class="line" line="17"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">cat dist/api-contract.json
</span></span><span class="line" line="18"><span style="--shiki-default:#22863A">  artifacts</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">    paths</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="20"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#032F62">dist/api-contract.json
</span></span><span class="line" line="21"><span style="--shiki-default:#22863A">    expire_in</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">1 hour
</span></span><span class="line" line="22"><span emptyLinePlaceholder>
</span></span><span class="line" line="23"><span style="--shiki-default:#22863A">test-frontend</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="26"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;All frontend tests passed!&quot;
</span></span><span class="line" line="27"><span emptyLinePlaceholder>
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">trigger-backend-pipeline</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="29"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">trigger-backend
</span></span><span class="line" line="30"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="31"><span style="--shiki-default:#22863A">    project</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">my-org/backend-service
</span></span><span class="line" line="32"><span style="--shiki-default:#22863A">    branch</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">main
</span></span><span class="line" line="33"><span style="--shiki-default:#22863A">    strategy</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">depend
</span></span><span class="line" line="34"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="35"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span></code></pre><pre className="language-yaml shiki shiki-themes github-light" code="# backend repo: .gitlab-ci.yml
stages:
  - build
  - test

build-backend:
  stage: build
  script:
    - echo &quot;All backend tests passed!&quot;

integration-test:
  stage: test
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;pipeline&quot;
  script:
    - echo &quot;Fetching API contract from frontend...&quot;
    - |
      curl --silent --fail \
        --header &quot;JOB-TOKEN: $CI_JOB_TOKEN&quot; \
        --output api-contract.json \
        &quot;${CI_API_V4_URL}/projects/${FRONTEND_PROJECT_ID}/jobs/artifacts/main/raw/dist/api-contract.json?job=build-frontend&quot;
    - cat api-contract.json
    - |
      if grep -q &#39;&quot;breaking_changes&quot;: true&#39; api-contract.json; then
        echo &quot;FAIL: Breaking API changes detected - backend integration blocked!&quot;
        exit 1
      fi
      echo &quot;PASS: API contract is compatible!&quot;
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># backend repo: .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="5"><span emptyLinePlaceholder>
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">build-backend</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;All backend tests passed!&quot;
</span></span><span class="line" line="10"><span emptyLinePlaceholder>
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">integration-test</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;pipeline&quot;
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="16"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Fetching API contract from frontend...&quot;
</span></span><span class="line" line="17"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#D73A49">|
</span></span><span class="line" line="18"><span style="--shiki-default:#032F62">      curl --silent --fail \
</span></span><span class="line" line="19"><span style="--shiki-default:#032F62">        --header &quot;JOB-TOKEN: $CI_JOB_TOKEN&quot; \
</span></span><span class="line" line="20"><span style="--shiki-default:#032F62">        --output api-contract.json \
</span></span><span class="line" line="21"><span style="--shiki-default:#032F62">        &quot;${CI_API_V4_URL}/projects/${FRONTEND_PROJECT_ID}/jobs/artifacts/main/raw/dist/api-contract.json?job=build-frontend&quot;
</span></span><span class="line" line="22"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">cat api-contract.json
</span></span><span class="line" line="23"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#D73A49">|
</span></span><span class="line" line="24"><span style="--shiki-default:#032F62">      if grep -q &#39;&quot;breaking_changes&quot;: true&#39; api-contract.json; then
</span></span><span class="line" line="25"><span style="--shiki-default:#032F62">        echo &quot;FAIL: Breaking API changes detected - backend integration blocked!&quot;
</span></span><span class="line" line="26"><span style="--shiki-default:#032F62">        exit 1
</span></span><span class="line" line="27"><span style="--shiki-default:#032F62">      fi
</span></span><span class="line" line="28"><span style="--shiki-default:#032F62">      echo &quot;PASS: API contract is compatible!&quot;
</span></span></code></pre><p>A few things worth noting in this config. The <code className="">integration-test</code> job uses <code className="">$CI_PIPELINE_SOURCE == &quot;pipeline&quot;</code> to ensure it only runs when triggered by an upstream pipeline, not on a standalone push to the backend repo. The frontend project ID is referenced via <code className="">$FRONTEND_PROJECT_ID</code>, which should be set as a <a href="https://docs.gitlab.com/ci/variables/" rel="">CI/CD variable</a> in the backend project settings to avoid hardcoding it.</p><p>Why it matters: Cross-service breakage that previously surfaced in production gets caught in the pipeline instead. The dependency between services stops being invisible and becomes something teams can see, track, and act on.</p><p><img alt="Cross-project pipelines" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738762/Blog/Imported/hackathon-fake-blog-post-s/image4_h6mfsb.png" title="Cross-project pipelines" /></p><h2 id="_3-multi-tenant-matrix-deployments-dynamic-child-pipelines">3. Multi-tenant / matrix deployments: Dynamic child pipelines</h2><p>The problem: You deploy the same application to 15 customer environments, or three cloud regions, or dev/staging/prod. Updating a deploy stage across all of them one by one is the kind of work that leads to configuration drift. Writing a separate pipeline for each environment is unmaintainable from day one.</p><p>GitLab&#39;s <a href="https://docs.gitlab.com/ci/pipelines/downstream_pipelines/#dynamic-child-pipelines" rel="">dynamic child pipelines</a> let you generate a pipeline at runtime. A job runs a script that produces a YAML file, and that YAML becomes the pipeline for the next stage. The pipeline structure itself becomes data.</p><pre className="language-yaml shiki shiki-themes github-light" code="# .gitlab-ci.yml
stages:
  - generate
  - trigger-environments

generate-config:
  stage: generate
  script:
    - |
      # ENVIRONMENTS can be passed as a CI variable or read from a config file.
      # Default to dev, staging, prod if not set.
      ENVIRONMENTS=${ENVIRONMENTS:-&quot;dev staging prod&quot;}
      for ENV in $ENVIRONMENTS; do
        cat &gt; ${ENV}-pipeline.yml &lt;&lt; EOF
      stages:
        - deploy
        - verify
      deploy-${ENV}:
        stage: deploy
        script:
          - echo &quot;Deploying to ${ENV} environment&quot;
      verify-${ENV}:
        stage: verify
        script:
          - echo &quot;Running smoke tests on ${ENV}&quot;
      EOF
      done
  artifacts:
    paths:
      - &quot;*.yml&quot;
    exclude:
      - &quot;.gitlab-ci.yml&quot;

.trigger-template:
  stage: trigger-environments
  trigger:
    strategy: depend

trigger-dev:
  extends: .trigger-template
  trigger:
    include:
      - artifact: dev-pipeline.yml
        job: generate-config

trigger-staging:
  extends: .trigger-template
  needs: [trigger-dev]
  trigger:
    include:
      - artifact: staging-pipeline.yml
        job: generate-config

trigger-prod:
  extends: .trigger-template
  needs: [trigger-staging]
  trigger:
    include:
      - artifact: prod-pipeline.yml
        job: generate-config
  when: manual
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">generate
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">trigger-environments
</span></span><span class="line" line="5"><span emptyLinePlaceholder>
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">generate-config</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">generate
</span></span><span class="line" line="8"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#D73A49">|
</span></span><span class="line" line="10"><span style="--shiki-default:#032F62">      # ENVIRONMENTS can be passed as a CI variable or read from a config file.
</span></span><span class="line" line="11"><span style="--shiki-default:#032F62">      # Default to dev, staging, prod if not set.
</span></span><span class="line" line="12"><span style="--shiki-default:#032F62">      ENVIRONMENTS=${ENVIRONMENTS:-&quot;dev staging prod&quot;}
</span></span><span class="line" line="13"><span style="--shiki-default:#032F62">      for ENV in $ENVIRONMENTS; do
</span></span><span class="line" line="14"><span style="--shiki-default:#032F62">        cat &gt; ${ENV}-pipeline.yml &lt;&lt; EOF
</span></span><span class="line" line="15"><span style="--shiki-default:#032F62">      stages:
</span></span><span class="line" line="16"><span style="--shiki-default:#032F62">        - deploy
</span></span><span class="line" line="17"><span style="--shiki-default:#032F62">        - verify
</span></span><span class="line" line="18"><span style="--shiki-default:#032F62">      deploy-${ENV}:
</span></span><span class="line" line="19"><span style="--shiki-default:#032F62">        stage: deploy
</span></span><span class="line" line="20"><span style="--shiki-default:#032F62">        script:
</span></span><span class="line" line="21"><span style="--shiki-default:#032F62">          - echo &quot;Deploying to ${ENV} environment&quot;
</span></span><span class="line" line="22"><span style="--shiki-default:#032F62">      verify-${ENV}:
</span></span><span class="line" line="23"><span style="--shiki-default:#032F62">        stage: verify
</span></span><span class="line" line="24"><span style="--shiki-default:#032F62">        script:
</span></span><span class="line" line="25"><span style="--shiki-default:#032F62">          - echo &quot;Running smoke tests on ${ENV}&quot;
</span></span><span class="line" line="26"><span style="--shiki-default:#032F62">      EOF
</span></span><span class="line" line="27"><span style="--shiki-default:#032F62">      done
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">  artifacts</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="29"><span style="--shiki-default:#22863A">    paths</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="30"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#032F62">&quot;*.yml&quot;
</span></span><span class="line" line="31"><span style="--shiki-default:#22863A">    exclude</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="32"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#032F62">&quot;.gitlab-ci.yml&quot;
</span></span><span class="line" line="33"><span emptyLinePlaceholder>
</span></span><span class="line" line="34"><span style="--shiki-default:#22863A">.trigger-template</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="35"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">trigger-environments
</span></span><span class="line" line="36"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="37"><span style="--shiki-default:#22863A">    strategy</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">depend
</span></span><span class="line" line="38"><span emptyLinePlaceholder>
</span></span><span class="line" line="39"><span style="--shiki-default:#22863A">trigger-dev</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="40"><span style="--shiki-default:#22863A">  extends</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">.trigger-template
</span></span><span class="line" line="41"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="42"><span style="--shiki-default:#22863A">    include</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="43"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">artifact</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">dev-pipeline.yml
</span></span><span class="line" line="44"><span style="--shiki-default:#22863A">        job</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">generate-config
</span></span><span class="line" line="45"><span emptyLinePlaceholder>
</span></span><span class="line" line="46"><span style="--shiki-default:#22863A">trigger-staging</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="47"><span style="--shiki-default:#22863A">  extends</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">.trigger-template
</span></span><span class="line" line="48"><span style="--shiki-default:#22863A">  needs</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">trigger-dev</span><span style="--shiki-default:#24292E">]
</span></span><span class="line" line="49"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="50"><span style="--shiki-default:#22863A">    include</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="51"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">artifact</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">staging-pipeline.yml
</span></span><span class="line" line="52"><span style="--shiki-default:#22863A">        job</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">generate-config
</span></span><span class="line" line="53"><span emptyLinePlaceholder>
</span></span><span class="line" line="54"><span style="--shiki-default:#22863A">trigger-prod</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="55"><span style="--shiki-default:#22863A">  extends</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">.trigger-template
</span></span><span class="line" line="56"><span style="--shiki-default:#22863A">  needs</span><span style="--shiki-default:#24292E">: [</span><span style="--shiki-default:#032F62">trigger-staging</span><span style="--shiki-default:#24292E">]
</span></span><span class="line" line="57"><span style="--shiki-default:#22863A">  trigger</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="58"><span style="--shiki-default:#22863A">    include</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="59"><span style="--shiki-default:#24292E">      - </span><span style="--shiki-default:#22863A">artifact</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">prod-pipeline.yml
</span></span><span class="line" line="60"><span style="--shiki-default:#22863A">        job</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">generate-config
</span></span><span class="line" line="61"><span style="--shiki-default:#22863A">  when</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">manual
</span></span></code></pre><p>The generation script loops over an <code className="">ENVIRONMENTS</code> variable rather than hardcoding each environment separately. Pass in a different list via a CI variable or read it from a config file and the pipeline adapts without touching the YAML. The trigger jobs use <a href="https://docs.gitlab.com/ci/yaml/#extends" rel="">extends:</a> to inherit shared configuration from <code className="">.trigger-template</code>, so <code className="">strategy: depend</code> is defined once rather than repeated on every trigger job. Add a new environment by updating the variable, not by duplicating pipeline config. Add <a href="https://docs.gitlab.com/ci/yaml/#when" rel="">when: manual</a> to the production trigger and you get a promotion gate baked right into the pipeline graph.</p><p>Why it matters: SaaS companies and platform teams use this pattern to manage dozens of environments without duplicating pipeline logic. The pipeline structure itself stays lean as the deployment matrix grows.</p><p><img alt="Dynamic pipeline" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738765/Blog/Imported/hackathon-fake-blog-post-s/image7_wr0kx2.png" title="Dynamic pipeline" /></p><h2 id="_4-mr-first-delivery-merge-request-pipelines-merged-results-and-workflow-routing">4. MR-first delivery: Merge request pipelines, merged results, and workflow routing</h2><p>The problem: Your pipeline runs on every push to every branch. Expensive tests run on feature branches that will never merge. Meanwhile, you have no guarantee that what you tested is actually what will land on <code className="">main</code> after a merge.</p><p>GitLab has three interlocking features that solve this together:</p><ul><li><a href="https://docs.gitlab.com/ci/pipelines/merge_request_pipelines/" rel="">Merge request pipelines</a> run only when a merge request exists, not on every branch push. This alone eliminates a significant amount of wasted compute.</li><li><a href="https://docs.gitlab.com/ci/pipelines/merged_results_pipelines/" rel="">Merged results pipelines</a> go further. GitLab creates a temporary merge commit (your branch plus the current target branch) and runs the pipeline against that. You are testing what will actually exist after the merge, not just your branch in isolation.</li><li><a href="https://docs.gitlab.com/ci/yaml/workflow/" rel="">Workflow rules</a> let you define exactly which pipeline type runs under which conditions and suppress everything else. The <code className="">$CI_OPEN_MERGE_REQUESTS</code> guard below prevents duplicate pipelines firing for both a branch and its open MR simultaneously.</li></ul><p>With those three working together, here is what a tiered pipeline looks like:</p><pre className="language-yaml shiki shiki-themes github-light" code="# .gitlab-ci.yml
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
    - if: $CI_COMMIT_BRANCH &amp;&amp; $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH
    - if: $CI_PIPELINE_SOURCE == &quot;schedule&quot;

stages:
  - fast-checks
  - expensive-tests
  - deploy

lint-code:
  stage: fast-checks
  script:
    - echo &quot;Running linter&quot;
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;push&quot;
    - if: $CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;

unit-tests:
  stage: fast-checks
  script:
    - echo &quot;Running unit tests&quot;
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;push&quot;
    - if: $CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;

integration-tests:
  stage: expensive-tests
  script:
    - echo &quot;Running integration tests (15 min)&quot;
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;

e2e-tests:
  stage: expensive-tests
  script:
    - echo &quot;Running E2E tests (30 min)&quot;
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;

nightly-comprehensive-scan:
  stage: expensive-tests
  script:
    - echo &quot;Running full nightly suite (2 hours)&quot;
  rules:
    - if: $CI_PIPELINE_SOURCE == &quot;schedule&quot;

deploy-production:
  stage: deploy
  script:
    - echo &quot;Deploying to production&quot;
  rules:
    - if: $CI_COMMIT_BRANCH == &quot;main&quot;
      when: manual
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">workflow</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="4"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
</span></span><span class="line" line="5"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH &amp;&amp; $CI_OPEN_MERGE_REQUESTS
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">      when</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">never
</span></span><span class="line" line="7"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;schedule&quot;
</span></span><span class="line" line="9"><span emptyLinePlaceholder>
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">fast-checks
</span></span><span class="line" line="12"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">expensive-tests
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">deploy
</span></span><span class="line" line="14"><span emptyLinePlaceholder>
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">lint-code</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="16"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">fast-checks
</span></span><span class="line" line="17"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="18"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running linter&quot;
</span></span><span class="line" line="19"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="20"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;push&quot;
</span></span><span class="line" line="21"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
</span></span><span class="line" line="22"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span><span class="line" line="23"><span emptyLinePlaceholder>
</span></span><span class="line" line="24"><span style="--shiki-default:#22863A">unit-tests</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="25"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">fast-checks
</span></span><span class="line" line="26"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="27"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running unit tests&quot;
</span></span><span class="line" line="28"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="29"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;push&quot;
</span></span><span class="line" line="30"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
</span></span><span class="line" line="31"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span><span class="line" line="32"><span emptyLinePlaceholder>
</span></span><span class="line" line="33"><span style="--shiki-default:#22863A">integration-tests</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="34"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">expensive-tests
</span></span><span class="line" line="35"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="36"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running integration tests (15 min)&quot;
</span></span><span class="line" line="37"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="38"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
</span></span><span class="line" line="39"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span><span class="line" line="40"><span emptyLinePlaceholder>
</span></span><span class="line" line="41"><span style="--shiki-default:#22863A">e2e-tests</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="42"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">expensive-tests
</span></span><span class="line" line="43"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="44"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running E2E tests (30 min)&quot;
</span></span><span class="line" line="45"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="46"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;merge_request_event&quot;
</span></span><span class="line" line="47"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span><span class="line" line="48"><span emptyLinePlaceholder>
</span></span><span class="line" line="49"><span style="--shiki-default:#22863A">nightly-comprehensive-scan</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="50"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">expensive-tests
</span></span><span class="line" line="51"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="52"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Running full nightly suite (2 hours)&quot;
</span></span><span class="line" line="53"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="54"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_PIPELINE_SOURCE == &quot;schedule&quot;
</span></span><span class="line" line="55"><span emptyLinePlaceholder>
</span></span><span class="line" line="56"><span style="--shiki-default:#22863A">deploy-production</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="57"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">deploy
</span></span><span class="line" line="58"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="59"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Deploying to production&quot;
</span></span><span class="line" line="60"><span style="--shiki-default:#22863A">  rules</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="61"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">if</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$CI_COMMIT_BRANCH == &quot;main&quot;
</span></span><span class="line" line="62"><span style="--shiki-default:#22863A">      when</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">manual
</span></span></code></pre><p>With this setup, the pipeline behaves differently depending on context. A push to a feature branch with no open MR runs lint and unit tests only. Once an MR is opened, the workflow rules switch from a branch pipeline to an MR pipeline, and the full integration and E2E suite runs against the merged result. Merging to <code className="">main</code> queues a manual production deployment. A nightly schedule runs the comprehensive scan once, not on every commit.</p><p>Why it matters: Teams routinely cut CI costs significantly with this pattern, not by running fewer tests, but by running the right tests at the right time. Merged results pipelines catch the class of bugs that only appear after a merge, before they ever reach <code className="">main</code>.</p><p><img alt="Conditional pipelines (within a branch with no MR)" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738768/Blog/Imported/hackathon-fake-blog-post-s/image6_dnfcny.png" title="Conditional pipelines (within a branch with no MR)" /></p><p><img alt="Conditional pipelines (within an MR)" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738772/Blog/Imported/hackathon-fake-blog-post-s/image1_wyiafu.png" title="Conditional pipelines (within an MR)" /></p><p><img alt="Conditional pipelines (on the main branch)" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738774/Blog/Imported/hackathon-fake-blog-post-s/image5_r6lkfd.png" title="Conditional pipelines (on the main branch)" /></p><h2 id="_5-governed-pipelines-cicd-components">5. Governed pipelines: CI/CD Components</h2><p>The problem: Your platform team has defined the right way to build, test, and deploy. But every team has their own <code className="">.gitlab-ci.yml</code> with subtle variations. Security scanning gets skipped. Deployment standards drift. Audits are painful.</p><p>GitLab <a href="https://docs.gitlab.com/ci/components/" rel="">CI/CD Components</a> let platform teams publish versioned, reusable pipeline building blocks. Application teams consume them with a single <code className="">include:</code> line and optional inputs — no copy-paste, no drift. Components are discoverable through the <a href="https://docs.gitlab.com/ci/components/#cicd-catalog" rel="">CI/CD Catalog</a>, which means teams can find and adopt approved building blocks without needing to go through the platform team directly.</p><p>Here is a component definition from a shared library:</p><pre className="language-yaml shiki shiki-themes github-light" code="# templates/deploy.yml
spec:
  inputs:
    stage:
      default: deploy
    environment:
      default: production
---
deploy-job:
  stage: $[[ inputs.stage ]]
  script:
    - echo &quot;Deploying $APP_NAME to $[[ inputs.environment ]]&quot;
    - echo &quot;Deploy URL: $DEPLOY_URL&quot;
  environment:
    name: $[[ inputs.environment ]]
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># templates/deploy.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">spec</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">  inputs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">    stage</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="5"><span style="--shiki-default:#22863A">      default</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">deploy
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">    environment</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#22863A">      default</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">production
</span></span><span class="line" line="8"><span style="--shiki-default:#6F42C1">---
</span></span><span class="line" line="9"><span style="--shiki-default:#22863A">deploy-job</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">  stage</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$[[ inputs.stage ]]
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">  script</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="12"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#032F62">echo &quot;Deploying $APP_NAME to $[[ inputs.environment ]]&quot;
</span></span><span class="line" line="13"><span style="--shiki-default:#24292E">    - </span><span style="--shiki-default:#22863A">echo &quot;Deploy URL</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$DEPLOY_URL&quot;
</span></span><span class="line" line="14"><span style="--shiki-default:#22863A">  environment</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="15"><span style="--shiki-default:#22863A">    name</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">$[[ inputs.environment ]]
</span></span></code></pre><p>And here is how an application team consumes it:</p><pre className="language-yaml shiki shiki-themes github-light" code="# Application repo: .gitlab-ci.yml
variables:
  APP_NAME: &quot;my-awesome-app&quot;
  DEPLOY_URL: &quot;https://api.example.com&quot;

include:
  - component: gitlab.com/my-org/component-library/build@v1.0.6
  - component: gitlab.com/my-org/component-library/test@v1.0.6
  - component: gitlab.com/my-org/component-library/deploy@v1.0.6
    inputs:
      environment: staging

stages:
  - build
  - test
  - deploy
" language="yaml" meta="" style=""><code><span class="line" line="1"><span style="--shiki-default:#6A737D"># Application repo: .gitlab-ci.yml
</span></span><span class="line" line="2"><span style="--shiki-default:#22863A">variables</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="3"><span style="--shiki-default:#22863A">  APP_NAME</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;my-awesome-app&quot;
</span></span><span class="line" line="4"><span style="--shiki-default:#22863A">  DEPLOY_URL</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">&quot;https://api.example.com&quot;
</span></span><span class="line" line="5"><span emptyLinePlaceholder>
</span></span><span class="line" line="6"><span style="--shiki-default:#22863A">include</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="7"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">component</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab.com/my-org/component-library/build@v1.0.6
</span></span><span class="line" line="8"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">component</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab.com/my-org/component-library/test@v1.0.6
</span></span><span class="line" line="9"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#22863A">component</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">gitlab.com/my-org/component-library/deploy@v1.0.6
</span></span><span class="line" line="10"><span style="--shiki-default:#22863A">    inputs</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="11"><span style="--shiki-default:#22863A">      environment</span><span style="--shiki-default:#24292E">: </span><span style="--shiki-default:#032F62">staging
</span></span><span class="line" line="12"><span emptyLinePlaceholder>
</span></span><span class="line" line="13"><span style="--shiki-default:#22863A">stages</span><span style="--shiki-default:#24292E">:
</span></span><span class="line" line="14"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">build
</span></span><span class="line" line="15"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">test
</span></span><span class="line" line="16"><span style="--shiki-default:#24292E">  - </span><span style="--shiki-default:#032F62">deploy
</span></span></code></pre><p>Three lines of <code className="">include:</code> replace hundreds of lines of duplicated YAML. The platform team can push a security fix to <code className="">v1.0.7</code> and teams opt in on their own schedule — or the platform team can pin everyone to a minimum version. Either way, one change propagates everywhere instead of needing to be applied repo by repo.</p><p>Pair this with <a href="https://docs.gitlab.com/ci/resource_groups/" rel="">resource groups</a> to prevent concurrent deployments to the same environment, and <a href="https://docs.gitlab.com/ci/environments/protected_environments/" rel="">protected environments</a> to enforce approval gates - and you have a governed delivery platform where compliance is the default, not the exception.</p><p>Why it matters: This is the pattern that makes GitLab CI/CD scale across hundreds of teams. Platform engineering teams enforce compliance without becoming a bottleneck. Application teams get a fast path to a working pipeline without reinventing the wheel.</p><p><img alt="Component pipeline (imported jobs)" src="https://res.cloudinary.com/about-gitlab-com/image/upload/v1775738776/Blog/Imported/hackathon-fake-blog-post-s/image2_pizuxd.png" title="Component pipeline (imported jobs)" /></p><h2 id="putting-it-all-together">Putting it all together</h2><p>None of these features exist in isolation. The reason GitLab&#39;s pipeline model is worth understanding deeply is that these primitives compose:</p><ul><li>A monorepo uses parent-child pipelines, and each child uses DAG execution</li><li>A microservices platform uses multi-project pipelines, and each project uses MR pipelines with merged results</li><li>A governed platform uses CI/CD components to standardize the patterns above across every team</li></ul><p>Most teams discover one of these features when they hit a specific pain point. The ones who invest in understanding the full model end up with a delivery system that actually reflects how their engineering organization works, not a pipeline that fights it.</p><h2 id="other-patterns-worth-exploring">Other patterns worth exploring</h2><p>The five patterns above cover the most common structural pain points, but GitLab&#39;s pipeline model goes further. A few others worth looking into as your needs grow:</p><ul><li><a href="https://docs.gitlab.com/ci/environments/" rel="">Review apps with dynamic environments</a> let you spin up a live preview for every feature branch and tear it down automatically when the MR closes. Useful for teams doing frontend work or API changes that need stakeholder sign-off before merging.</li><li><a href="https://docs.gitlab.com/ci/caching/" rel="">Caching and artifact strategies</a> are often the fastest way to cut pipeline runtime after the structural work is done. Structuring <code className="">cache:</code> keys around dependency lockfiles and being deliberate about what gets passed between jobs with <a href="https://docs.gitlab.com/ci/yaml/#artifacts" rel="">artifacts:</a> can make a significant difference without changing your pipeline shape at all.</li><li><a href="https://docs.gitlab.com/ci/pipelines/schedules/" rel="">Scheduled and API-triggered pipelines</a> are worth knowing about because not everything should run on a code push. Nightly security scans, compliance reports, and release automation are better modeled as scheduled or <a href="https://docs.gitlab.com/ci/triggers/" rel="">API-triggered</a> pipelines with <code className="">$CI_PIPELINE_SOURCE</code> routing the right jobs for each context.</li></ul><h2 id="how-to-get-started">How to get started</h2><p>Modern software delivery is complex. Teams are managing monorepos with dozens of services, coordinating across multiple repositories, deploying to many environments at once, and trying to keep standards consistent as organizations grow. GitLab&#39;s pipeline model was built with all of that in mind.</p><p>What makes it worth investing time in is how well the pieces fit together. Parent-child pipelines bring structure to large codebases. Multi-project pipelines make cross-team dependencies visible and testable. Dynamic pipelines turn environment management into something that scales gracefully. MR-first delivery with merged results ensures confidence at every step of the review process. And CI/CD Components give platform teams a way to share best practices across an entire organization without becoming a bottleneck.</p><p>Each of these features is powerful on its own, and even more so when combined. GitLab gives you the building blocks to design a delivery system that fits how your team actually works, and grows with you as your needs evolve.</p><blockquote><p><a href="https://about.gitlab.com/free-trial/" rel="">Start a free trial of GitLab Ultimate</a> to use pipeline logic today.</p></blockquote><h2 id="read-more">Read more</h2><ul><li><a href="https://about.gitlab.com/blog/variable-and-artifact-sharing-in-gitlab-parent-child-pipelines/" rel="">Variable and artifact sharing in GitLab parent-child pipelines</a></li><li><a href="https://about.gitlab.com/blog/ci-cd-inputs-secure-and-preferred-method-to-pass-parameters-to-a-pipeline/" rel="">CI/CD inputs: Secure and preferred method to pass parameters to a pipeline</a></li><li><a href="https://about.gitlab.com/blog/tutorial-how-to-set-up-your-first-gitlab-ci-cd-component/" rel="">Tutorial: How to set up your first GitLab CI/CD component</a></li><li><a href="https://about.gitlab.com/blog/how-to-include-file-references-in-your-ci-cd-components/" rel="">How to include file references in your CI/CD components</a></li><li><a href="https://about.gitlab.com/blog/faq-gitlab-ci-cd-catalog/" rel="">FAQ: GitLab CI/CD Catalog</a></li><li><a href="https://about.gitlab.com/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way/" rel="">Building a GitLab CI/CD pipeline for a monorepo the easy way</a></li><li><a href="https://about.gitlab.com/blog/a-ci-component-builders-journey/" rel="">A CI/CD component builder&#39;s journey</a></li><li><a href="https://about.gitlab.com/blog/ci-cd-catalog-goes-ga-no-more-building-pipelines-from-scratch/" rel="">CI/CD Catalog goes GA: No more building pipelines from scratch</a></li></ul><style>html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}</style>]]></content>
        <author>
            <name>Omid Khan</name>
            <uri>https://about.gitlab.com/blog/authors/omid-khan/</uri>
        </author>
        <published>2026-04-09T00:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[GitLab Patch Release: 18.10.3, 18.9.5, 18.8.9]]></title>
        <id>https://docs.gitlab.com/releases/patches/patch-release-gitlab-18-10-3-released/</id>
        <link href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-18-10-3-released/"/>
        <updated>2026-04-08T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<p>Learn more this patch release for GitLab Community Edition and Enterprise Edition.</p>]]></content>
        <published>2026-04-08T00:00:00.000Z</published>
    </entry>
</feed>