GitLab CI/CD Specialist cheat sheet
GitLab CI/CD Specialist · Keep the key ideas within reach.
Pipeline configuration and authoring
A
.gitlab-ci.ymlmust contain at least one job; a top-level key that is not a reserved keyword and not a job name causes a pipeline creation error.Reserved top-level keywords include stages, variables, default, include, workflow, image, services, cache, before_script, after_script, and pages; any other key is treated as a job name.
includesupports local, remote, template, and project sources;include:projectrequiresinclude:fileorinclude:ref, and nested includes are capped (default max depth 100).extendsperforms a reverse deep merge: the child overrides scalars, arrays are replaced rather than concatenated, and up to 11 levels of inheritance are allowed.YAML anchors (
&name/*name) and!referencetags deduplicate config;!referencecan pull a single key out of another job, including nested keys.default:sets image, services, cache, before_script, after_script, tags, and retry for all jobs; a job-level definition replaces the default rather than merging.scriptis the only required job keyword;before_scriptandafter_scriptrun per job, andafter_scriptruns in a separate shell so exported variables and cwd do not persist.Global
workflow:rulesgates whether a pipeline is created at all; job-levelrulesonly gate whether a given job is added.
Runners, executors, and job execution environment
Executor choice determines isolation: shell runs directly on the host, docker runs each job in a container, kubernetes runs each job in a pod, and docker-autoscaler provisions ephemeral containers.
A runner's
config.tomlholdsconcurrent(global parallelism),[[runners]]entries with url, token, executor, and[runners.docker]settings such as image, privileged, and volumes.Runner registration tokens are deprecated in favor of runner authentication tokens created in the UI/API; the token is stored in
config.tomland identifies the runner, not the user.Job tags are matched against runner tags; a job whose tags match no available runner stays pending with 'no runners that can run this job'.
tagson a job is an AND filter over the runner's tag set; the special tagdockeris not implicit and must be assigned explicitly.Protected runners only accept jobs on protected branches or protected tags; unprotected runners accept any job, so secrets should be paired with protected runners.
imageandservicesare ignored by the shell executor; the shell executor uses software installed on the runner host and inherits its environment.concurrenton the runner andresource_groupon the job both limit parallelism, but onlyresource_groupserializes jobs across runners for the same deployment target.
Variables, secrets, and protected configuration
Precedence, highest to lowest: trigger/manual pipeline variables, project variables, group variables, instance variables, then
.gitlab-ci.ymljob-level, then global YAML, then deployment variables.A variable marked protected is only exposed to pipelines on protected branches or tags; a variable marked masked must meet masking rules (min 8 chars, no whitespace, Base64/hex-safe charset).
Masked variables are redacted in job logs; masking is a log filter, not encryption, so a transformed value (e.g. base64-encoded) is not automatically masked.
variables:values are strings; booleans and numbers should be quoted, and$VARin a value is expanded at runtime unless escaped with$$.File-type variables write the value to a temporary file and set the variable to that path; use them for kubeconfig, certificates, and SSH keys.
CI/CD secrets from external managers (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager) are integrated via
secrets:withvault:,azure_key_vault:, orgcp_secret_manager:providers.id_tokensissues an OIDC JWT scoped to the job'saudclaim; it is the supported way to authenticate to cloud providers without storing long-lived credentials.Predefined variables such as CI_COMMIT_REF_PROTECTED, CI_PIPELINE_SOURCE, CI_JOB_TOKEN, and CI_REGISTRY_PASSWORD are read-only and cannot be overridden in YAML.
Pipeline efficiency: caching, artifacts, and parallelism
Cache is a best-effort optimization stored on the runner (local, S3, GCS, Azure); artifacts are uploaded to GitLab and are guaranteed to be passed to later stages.
Cache key should include a lockfile hash (e.g.
key: files: [package-lock.json]) so dependency changes invalidate the cache; a static key risks stale dependencies.cache:key:filescomputes a SHA over the listed files, andcache:key:prefixcombines that SHA with a literal string.Artifacts support
paths,exclude,expire_in,when(on_success, on_failure, always), andreports:for JUnit, coverage, SAST, and dependency scanning.dependenciesrestricts which prior jobs' artifacts a job downloads; without it, a job downloads artifacts from all jobs in earlier stages.parallel: Ncreates N jobs with CI_NODE_INDEX and CI_NODE_TOTAL;parallel:matrixexpands over named dimensions and produces one job per combination.needsbuilds a DAG that ignores stage order; jobs with needs start as soon as their dependencies finish, andneeds: []starts a job immediately.interruptible: truelets a new pipeline cancel the running job when auto-cancel redundancies is enabled;resource_groupserializes jobs that touch the same environment.
Jobs orchestration: rules, needs, stages, and triggers
Stages run in the order declared in
stages; jobs in the same stage run in parallel, and a failing job blocks later stages unlessallow_failure: trueorwhen: manual.rulesare evaluated top to bottom; the first matching rule wins, andwhen: neverin that rule excludes the job.only/exceptare legacy and cannot be mixed withrulesin the same job.rules:changescompares against the previous commit on branches and against the target branch on merge requests; it is always true on new branches and scheduled pipelines.rules:ifsupports CI_PIPELINE_SOURCE, CI_COMMIT_BRANCH, CI_COMMIT_TAG, CI_MERGE_REQUEST_* variables; use$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHfor default-branch gating.whenvalues are on_success, on_failure, always, manual, delayed, and never;when: delayedrequiresstart_in(e.g.start_in: 30 minutes).triggerstarts a downstream pipeline, either as a multi-project pipeline (withprojectandbranch) or a child pipeline (withinclude); child pipelines appear in the parent's pipeline graph.strategy: dependon a trigger makes the parent job status mirror the downstream pipeline; without it the parent succeeds when the trigger is created.environmentwithaction: stopandon_stopdefines a teardown job; environments track deployments and enable review apps and rollback.
Security, compliance, and troubleshooting pipelines
Protected environments restrict who can deploy and require approval rules; deployment jobs targeting them must run on protected branches to access protected variables.
CI_JOB_TOKENgrants limited API access scoped to the project's allowlist; it is short-lived and should not be confused with a personal or project access token.Secret detection, SAST, dependency scanning, container scanning, and license scanning are configured via
include: templateor the Security Configuration UI and publish reports underartifacts:reports.allow_failure: exit_codeslets specific exit codes pass a job, which is how security scanners report findings without failing the pipeline.Common failure: 'This job is stuck because no runners online' means tag mismatch, runner paused, or protected-runner/branch mismatch - check runner tags and CI_COMMIT_REF_PROTECTED.
Common failure: YAML invalid - use CI Lint (
/ci/lint) or the API/projects/:id/ci/lint; a leading tab, duplicate key, or unresolvable!referencebreaks the whole pipeline.Job logs are capped (default 4 MB per job trace); increase
ci_jobs_trace_size_limitor reduce verbosity, since truncated logs hide the real error.retryacceptsmaxandwhen(always, unknown_failure, script_failure, runner_system_failure, stuck_or_timeout_failure) to auto-retry flaky infrastructure failures.