GitLab CI

The integrated DevSecOps platform — SCM + CI + container registry + SAST/DAST + dependency scanning in one product. .gitlab-ci.yml stages, shared/group/specific runners, Auto DevOps, child pipelines, dynamic environments, OIDC to clouds.

Overview

GitLab CI and the integrated platform

GitLab CI is the CI half of the integrated GitLab DevSecOps platform: SCM, CI/CD, container registry, package registry, security scanning and issue tracking in one product. JetBrains 2024 DevEcosystem puts it at ~21% share, third behind GitHub Actions (~33%) and Jenkins (~28%).

The pitch is integration. GHA couples CI tightly to GitHub, but you stitch in registry, scanning and deploy from third parties; GitLab gives the whole vertical stack from one vendor. For some orgs that is the right trade (one auth model, one billing relationship, one dashboard); for others it is lock-in or feature surface they don't need.

When to pick GitLab CI

  • Already on GitLab — The integration tax of anything else doesn't pay off; .gitlab-ci.yml is the natural fit
  • Integrated DevSecOps reporting — Vulnerability dashboard, license compliance, SAST + DAST + SCA in one MR widget, instead of bolting Snyk/Aqua/Sonar onto GHA
  • Self-managed (on-prem) requirement — GitLab Self-Managed runs the whole platform on your infrastructure: better UX than self-managed Jenkins, more cohesive than GitHub Enterprise Server. Common in banking, government, defense
  • Compliance and governance — Compliance Pipelines run on every project regardless of what the project team does; org-level required jobs
  • Mid-size companies wanting one platform — "One tool that does it all"
  • Already on GitHub — The integration tax runs the other way; GHA + Dependabot + GHCR + Code Scanning covers more than people credit
  • Max ecosystem reach — GHA's marketplace is significantly larger: thousands more community actions than GitLab CI components
  • Cost-sensitive at scale — GitLab.com Ultimate (which includes DAST/SAST) is $99/user/month; GHA Pro is $4/user/month

Three load-bearing concepts

  • Workflow rules — At the top of .gitlab-ci.yml they decide the pipeline kind. Without them GitLab creates both branch AND MR pipelines for the same commit (the "duplicate pipeline" problem). Standard pattern: MR pipelines for non-default branches, branch pipelines for the default only
  • Merge train — GitLab's merge queue: serializes MR merges with simulated-rebase pipelines so "all green individually, red after merge" doesn't happen. A Premium feature; canonical for high-traffic main branches
  • Child and dynamic child pipelines — A parent pipeline detects which paths changed and triggers a child pipeline for that subset. Generating the child .yml as a job artifact makes it fully programmatic

Key concepts

.gitlab-ci.yml structure
Lives at repo root. Single root, stages + jobs: Note resource_group: deploy-prod creates a mutex — only one pipeline can be in this job at a time. Equivalent of GHA's concurrency: { group: ..., cancel-in-progress: false }.
Workflow rules + duplicate pipeline problem
Without explicit workflow rules, GitLab creates BOTH a branch pipeline AND an MR pipeline for the same commit when a branch has an open MR. Wastes runner minutes; confuses status checks. The fix: This means: any push to a feature branch with an open MR runs only the MR pipeline. Push to main runs the branch pipeline. Tags run their own. Everything else gets no pipeline. Inverse pattern — branch pipelines for everything except when an MR exists: The GitLab docs call this the "duplicate pipeline" problem and offer canonical recipes. Always start with explicit workflow rules.
Runners + executors
Three categories by ownership: Shared runners. GitLab.com-hosted. Free tier: 400 CI minutes/month for private projects, unlimited for public OSS. Paid tiers: 10k-50k minutes. Use for OSS, small teams, CI bursts. Group runners. Self-hosted at the GitLab group level. Shared across all projects in the group. Use for company-wide self-hosted runners with consistent config (e.g., a fleet of K8s-executor runners for the whole engineering org). Project runners. Self-hosted per project. Isolated. Use for projects with unique requirements (GPU, specific OS, on-prem dependencies). Six executors: shell — runs jobs as shell commands directly on the runner host. Persistent state between jobs (the supply-chain footgun). Avoid except for legacy. docker — runs each job in a fresh Docker container. The popular default. State doesn't persist between jobs (each job: fresh container). Privileged Docker access requires running runner in privileged mode (security risk). kubernetes — runs each job in a fresh K8s pod. Modern default. Pod is destroyed at job end. ServiceAccount-scoped permissions. Combined with cluster-autoscaler / Karpenter, you get elastic CI capacity. Equivalent of GHA ARC. docker-machine — auto-scales VMs on cloud (AWS, GCP, etc.). Older, deprecated path; use kubernetes executor instead in 2026. ssh — runs on remote SSH host. For specific hardware that can't be containerized. virtualbox / hyperv / parallels — VM executors for OS-specific builds (Windows-on-Mac, etc.). Recommended: kubernetes executor with autoscaling for the modern stack. Helm chart gitlab-runner installs the runner-controller; jobs spawn as pods.
Auto DevOps
Canned .gitlab-ci.yml that auto-detects your language and runs the full DevSecOps cycle without user-written CI config. Enable in project settings → CI/CD → Auto DevOps. Behind the scenes, GitLab includes an internal Auto-DevOps.gitlab-ci.yml that: 1. Detects language via Heroku-style buildpack auto-detection. 2. Builds with Auto Build (typically using Cloud Native Buildpacks). 3. Runs Auto Test (language-appropriate test runner). 4. Code Quality (Code Climate-style metrics). 5. SAST, Secret Detection, Dependency Scanning (always-on). 6. Container Scanning on the built image. 7. DAST against the review app. 8. License Compliance. 9. Auto Deploy to Kubernetes via Helm (review app per branch, staging on default branch, production on tag). Use cases: - Greenfield prototyping — instant CI/CD with sensible defaults. - Internal tools where the team doesn't want to write CI. Limitations: - Opinionated — heavy customization fights the auto-template. - Helm-based deploy assumes a specific cluster setup (cluster integration in GitLab settings). - Most production projects override the template with explicit jobs after they outgrow defaults. Pattern: start with Auto DevOps to bootstrap; gradually replace stages with explicit jobs as you need control. The Auto-DevOps.gitlab-ci.yml is itself includable — include: template: Auto-DevOps.gitlab-ci.yml — so you can pull in just the parts you want and override the rest.
OIDC to AWS / GCP / Azure
Same pattern as GHA OIDC. Each job mints a JWT; cloud STS validates and returns short-lived credentials. Job declares id_tokens with a custom audience: The IAM role's trust policy validates the JWT: The sub claim restricts which project + ref can assume the role. Same security pattern as GHA. By 2026 this replaces stored AWS keys in GitLab's CI/CD variables.
Recipe: monorepo with dynamic child pipelines
Pattern for a 30-service monorepo where each service has its own pipeline: Each services/$svc/ci.yml fragment looks like: Behavior: PR touches only services/payments → only payments builds, tests, deploys. Fan-out is implicit; unchanged services don't run. Equivalent of paths-filter + Turborepo affected-only in GHA, but expressed as native GitLab CI dynamic pipelines.
Recipe: review app per MR with stop environment
Deploy a unique preview environment for every MR, automatically destroyed when the MR closes: What this does: each MR opens a deploy job that creates a unique namespace + Helm release at .review.example.com. The MR widget shows a "View deployment" button linking to that URL. Reviewers, PMs, designers can interact with the actual deployed feature in the MR. When MR closes/merges, GitLab triggers stop_review (auto-via on_stop or manual button). Cleanup destroys the namespace. auto_stop_in: 1 week is a safety net — stale review apps auto-destroy after a week, preventing orphan namespaces if someone forgets to close MRs. DAST runs against the review app — the dynamic security scan exercises the actual deployed feature. This is the pattern Vercel/Netlify popularized for static sites; GitLab provides the primitives to do it for any K8s-deployed app.
Recipe: merge train for high-traffic main
Merge train serializes MR merges with simulated-rebase pipelines: Configure merge train in project settings → Merge Requests → enable "Merge train". Optional: "Pipelines must succeed" + "Merge in order" require pipelines green before joining train. Train operation: 1. MR-1 author clicks "Merge when pipeline succeeds (and add to train)". 2. GitLab creates a merge_train pipeline that simulates merging MR-1 onto current target branch. 3. If MR-1 pipeline succeeds, merge happens. 4. MR-2 added to train: GitLab creates merge_train pipeline simulating MR-2 merged AFTER MR-1's merged state. 5. If MR-2 pipeline succeeds, merge happens (MR-1 already merged at this point). 6. If MR-2 pipeline fails, MR-2 is removed from train; subsequent MRs continue. interruptible: true on jobs lets train rebuild faster — when MR-3 is added to a train where MR-2 is still running, MR-2's pipeline cancels and restarts atop MR-3. Without interruptible:, train pipelines are slower. Equivalent of GHA's merge queue (GA 2023). Solves the "all green individually but red after merge" race condition. Mandatory for high-traffic main branches in 2026.
Recipe: matrix + parallel for cross-platform tests
Two GitLab CI primitives for parallel execution: parallel: N — run the same job N times with different CI_NODE_INDEX: CI_NODE_INDEX is 1..N; CI_NODE_TOTAL is N. Test runner consumes them to shard tests by timing or hash. parallel:matrix — cross-product of variables: That's 2×3 + 1×1 = 7 jobs in parallel. Each job has $OS and $NODE set. The runner with matching tag (windows / linux / macos) executes. Combined: parallel:matrix declares the cross-product, then add parallel:N to each matrix entry to shard within. Possible but rarely needed; usually one or the other. Compared to GHA matrix: GitLab's parallel:matrix has slightly more flexible shape (multiple matrix entries with different inclusions), but GHA's matrix:include lets you add specific extras. Roughly equivalent expressivity.
Recipe: Compliance Pipelines for org-level governance
Org-level pipelines that run on every project regardless of project's own .gitlab-ci.yml. Used for required compliance jobs. Setup at the group level → Settings → Compliance → Compliance frameworks. Define a framework with a pipeline configuration: Apply the framework to specific projects via project settings or group default. Once applied, every pipeline run on that project runs the compliance jobs in addition to project-defined jobs. Project teams can't bypass them. Use cases: - Security: secret scan, SBOM generation, supply-chain attestation on every build. - Legal: license scan, code provenance. - Audit: deploy logs, change records to immutable storage. - Regulatory (SOC 2, HIPAA, FedRAMP): mandated jobs running on every release. Equivalent in GHA: required workflows (org-level) introduced in 2023 — similar concept, less mature reporting integration than GitLab's Vulnerability dashboard.

When to use it

  • Already on GitLab — the integrated platform value compounds
  • Self-managed CI/CD requirement (regulated, on-prem) where Jenkins's UX is too rough
  • Want SAST/DAST/SCA/license compliance integrated, not bolted on
  • Compliance Pipelines for org-level mandatory jobs
  • Mid-size company that wants single-vendor for SCM + CI + registry + scanning

Interview questions

  • When does GitLab CI win over GitHub Actions?
  • Walk through the difference between branch pipeline, MR pipeline, merged-result pipeline, and merge train.
  • How do you build a monorepo CI in GitLab with dynamic child pipelines?
  • Walk through GitLab's integrated DevSecOps scanning — SAST, DAST, SCA, container, license.
  • How do GitLab runners scale on Kubernetes for a busy CI workload?
  • Quick-fire interview answers — GitLab CI essentials.

Sign up free to read the full topic

More DevOps topics

Start free on Cariara · Coding problems · System design studio