GitLab CI Handbook
Curated GitLab CI/CD guidance, verified against GitLab 18.x. This file is a router. Select the task bundle first and read every required reference before acting. Then add topic references for the configuration under review. When a reference points to another file for a safety or correctness constraint, read that file too. Do not load unrelated files.
Baseline
- Guidance targets GitLab 18+, Free tier, Linux runners, bash. Paid-tier or executor-specific requirements are flagged inline where they apply.
- For syntax not covered here, or when in doubt, check the official docs instead of guessing: keyword reference https://docs.gitlab.com/ci/yaml/, versioned archive https://archives.docs.gitlab.com/.
Task bundles
File names in this table live under references/.
| Task | Read before acting |
|---|---|
| Focused question or explanation | The matching topic owner from Routing, plus every safety or correctness reference it names |
| Create a complete pipeline | pipeline-structure.md, pipeline-selection.md, data-flow.md, execution-environment.md, bash-in-ci.md, security.md |
| Add or modify a job | pipeline-selection.md, then every topic owner from Routing that matches the changed keywords; read bash-in-ci.md when adding or changing commands |
| Full review or audit | pipeline-structure.md, pipeline-selection.md, data-flow.md, execution-environment.md, security.md, bash-in-ci.md, and the validation section in orchestration.md; add readability.md, informative-logging.md, developer-experience.md, and pipeline-ui.md when reviewing maintainability, diagnostics, or graph navigability |
| Pipeline or job missing | debugging.md, pipeline-selection.md, and the validation section in orchestration.md |
| Runner, image, service, or pre-script failure | debugging.md, execution-environment.md; add security.md for authentication, protected resources, or runner trust |
| Script failure | debugging.md, bash-in-ci.md; add data-flow.md for cache, artifact, report, or dependency-transfer failures |
| Optimize a pipeline | data-flow.md, execution-environment.md, orchestration.md, pipeline-selection.md |
| Pipeline graph or UI is too large | pipeline-ui.md, readability.md; add orchestration.md for child pipelines or matrices, pipeline-selection.md when reducing conditional topology, and data-flow.md before changing needs |
| Deploy or environment work | execution-environment.md, pipeline-selection.md, security.md |
| Components or includes | pipeline-structure.md, security.md, and the validation section in orchestration.md |
| Downstream, child, or matrix pipeline | orchestration.md, data-flow.md, pipeline-selection.md |
Routing
| Read | When the task involves |
|---|---|
references/pipeline-structure.md |
Creating or restructuring .gitlab-ci.yml; refactoring an oversized pipeline file safely; splitting config with include; CI/CD components (include:component), authoring and consuming them; extends vs anchors vs !reference; default: and hidden .base jobs; spec:inputs; repo layout for CI files; config merge/override questions |
references/pipeline-selection.md |
Which pipelines and jobs run: workflow:rules, job rules, rules:changes (symptoms: duplicate pipelines, job runs twice, job not triggering); reusable rule sets; tag release pipelines; scheduled jobs; manual gates; only/except deprecation |
references/data-flow.md |
Caching and cache keys, policies, misses; artifacts and reports; passing outputs between jobs; DAGs with needs; test sharding; checkout strategy (GIT_DEPTH); making a pipeline faster (measurement method and anti-patterns) |
references/execution-environment.md |
Runners and tags:; executors; choosing and pinning job images; private registry auth; sidecar services: (databases for integration tests); Docker image builds (dind); environments, review apps, resource_group; GitLab Pages |
references/orchestration.md |
Parent-child and multi-project pipelines; dynamic child pipelines; matrices (parallel:matrix); auto-cancel and retries (interruptible, retry); timeout budgeting; validating compiled configuration (CI Lint, merged_yaml, validation levels) |
references/pipeline-ui.md |
Pipeline graphs that are too wide, tall, dense, or slow to navigate; stage vs job-dependency views; mini graphs; grouped jobs; downstream cards; choosing native GitLab structure that keeps large pipelines understandable |
references/security.md |
Secrets storage and variable hygiene; fork MR pipelines; CI_JOB_TOKEN and its allowlist; OIDC id_tokens for cloud auth; runner isolation (privileged, shell executor); auditing third-party CI code |
references/debugging.md |
A failing or missing pipeline or job with a concrete symptom: error-text lookup, debug-in-runner-order, empty-variable confusions, predefined-variable traps |
references/bash-in-ci.md |
Writing or fixing script: / before_script: / after_script:; inline YAML vs scripts/*.sh decisions; set -Eeuo pipefail; required-env-var checks; quoting; shellcheck; why a multiline block didn't fail; how the runner executes commands |
references/readability.md |
Naming jobs, stages, variables, or CI files; commenting style; making a pipeline navigable for newcomers |
references/informative-logging.md |
What jobs should echo (versions, decisions) and must never echo (secrets); collapsible log sections; variable masking behavior |
references/developer-experience.md |
Designing pipelines whose failures are debuggable: workflow:name pipeline titles; job execution headers; actionable failure messages; surfacing test reports and artifact links in MRs; diagnostic artifacts; reproducing CI failures locally |
Secrets questions span two files: log exposure and masking in
informative-logging.md, storage, tokens, and the wider threat model in
security.md. Read both.
Rules of engagement
When writing pipeline YAML or CI bash for a user:
- Follow the structure rules (no god YAML, but don't over-decompose
tiny pipelines):
pipeline-structure.md. - Extract bash to
scripts/ci/*.shwhen the criteria inbash-in-ci.mdsay so; short wiring stays inline, it is a balance, not extraction by default. Default extracted scripts toset -Eeuo pipefail; deviate when the script deliberately handles those conditions. Use intent-revealing names:bash-in-ci.md,readability.md. - For a complete pipeline, define
workflow:rulesdeliberately to prevent duplicate or unintended pipeline types; the verified pattern is inpipeline-selection.md. Do not replace an existing workflow when the user only asked for a job or config fragment. - Prefer a verified pattern from the pattern files
(
pipeline-selection.md,data-flow.md,execution-environment.md,orchestration.md) over inventing one; adapt names and rules to the project. - If available, validate generated config before handing it over, and
say which level was reached (levels and their limits: end of
orchestration.md). GitLab CI Lint for GitLab semantics,shellcheckfor shell scripts.yamllintandgitlab-ci-localare useful local checks, but they do not prove GitLab will compile the same pipeline.
When modifying an existing pipeline:
- Read the root file and every
include:localfile before touching anything; the pipeline is their merge, not the root file. - Match the project's conventions even when this handbook prefers
otherwise: their
rules:idioms (or legacyonly/except, noting the deprecation in passing), their.base-*jobs, their naming and stage layout. Do not re-declare whatdefault:already provides. In-repo consistency beats handbook preference for a small change; migrations are their own MR. - Make focused additions in the file where that domain lives; do not
rewrite or reformat surrounding config. Extending
stages:orworkflow:is a separate, called-out change. - When asked to make a pipeline faster: measure first, change one
bottleneck per round, report absolute numbers. Method and
anti-patterns: end of
data-flow.md.