GitLab CI/CD provides integrated pipeline orchestration directly within GitLab repositories, utilizing reusable CI Components and container-native runners for automated software delivery.
When to Use
- Self-Hosted & Enterprise GitOps CI/CD: Running pipelines within GitLab EE/CE and private runner infrastructures.
- Container Registry & Helm Package Integration: Built-in GitLab Container Registry, Package Registry, and Dependency Proxy.
- Multi-Project & Downstream Pipelines: Triggering coordinated cross-repository builds in complex enterprise architectures.
- Dynamic Parent-Child Pipelines: Generating build steps dynamically at runtime based on modified monorepo paths.
Quick Start
# .gitlab-ci.yml
stages:
- build
- test
build-job: stage: build image: node:20 script: - npm ci - npm run build artifacts: paths: - dist/
test-job: stage: test image: node:20 script: - npm test needs: [build-job]
## Core Concepts
### Declarative Pipeline with Stages, Caching & Artifacts
Clean, structured `.gitlab-ci.yml` pipeline:
```yaml
# .gitlab-ci.yml
stages:
- lint
- test
- build
- deploy
default:
image: node:22-alpine
cache:
key:
files:
- package-lock.json
paths:
- .npm/
variables:
npm_config_cache: "$CI_PROJECT_DIR/.npm"
lint:
stage: lint
script:
- npm ci
- npm run lint
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
test:
stage: test
script:
- npm ci
- npm test -- --ci --reporters=default --reporters=jest-junit
artifacts:
when: always
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
build-container:
stage: build
image: docker:27-cli
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Monorepo Path Filtering with rules:changes
Executing jobs only when relevant subdirectories are modified:
frontend-job:
stage: test
script:
- cd frontend && npm test
rules:
- changes:
- frontend/**/*
backend-job:
stage: test
script:
- cd backend && cargo test
rules:
- changes:
- backend/**/*
Protected Environments & Manual Deployment Gates
Requiring manual approval for production releases:
deploy-production:
stage: deploy
environment:
name: production
url: https://api.example.com
script:
- echo "Deploying version $CI_COMMIT_SHA to production cluster"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual # Requires manual trigger in GitLab UI
Common Patterns
Multi-Stage Pipeline with Artifact Passing and Rule Conditions
Problem: Running tests and security scans on draft branches before code is ready for deployment.
Solution:
Use .gitlab-ci.yml stages with rules: conditions:
stages:
- test
- deploy
run_tests:
stage: test
image: node:20-alpine
script:
- npm ci
- npm test
artifacts:
when: on_failure
paths:
- test-results/
deploy_prod:
stage: deploy
image: alpine/k8s:1.28.2
script:
- kubectl apply -f k8s/production/
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
Best Practices
Do:
- Use
rules:changesin monorepos to avoid running redundant jobs when unrelated code is modified. - Configure GitLab
reports:junitandreports:coverage_reportto view test insights in merge requests. - Use GitLab Dependency Proxy to cache container images from Docker Hub, eliminating rate limit throttling.
- Mark production deploy jobs with
when: manualand assign them to protected environments with approver policies.
Don't:
- Use deprecated
only/exceptsyntax; migrate to modernrules:directives. - Store plaintext passwords in
.gitlab-ci.yml; use Masked and Protected CI/CD Variables. - Run Docker-in-Docker (
dind) with privileged flags in shared environments; use Kaniko for rootless builds.
Troubleshooting
| Error | Cause | Solution |
|---|---|---|
yaml invalid: jobs:run_tests config key may not be used with |
Incompatible keyword combinations (e.g. only used with rules). |
Migrate legacy only/except syntax to modern rules: conditions. |
Job failed: execution took longer than ... |
Job exceeded runner timeout setting. | Increase timeout in project Settings > CI/CD > General pipelines. |
Artifacts not found in downstream job |
Artifact expiration reached or dependencies: list omitted. |
Explicitly declare dependencies: [build_job] in the consumer job. |