The .gitlab-ci.yml model
Stages, jobs, and scripts.
GitLab CI is defined by one file at the root of your repository: .gitlab-ci.yml. Unlike Jenkins, there is no controller to configure through a UI — the pipeline lives entirely in that YAML, versioned and reviewed with the code. GitLab reads it on every push and runs the jobs it describes. Learn its three core ideas — stages, jobs, and scripts — and you can read almost any GitLab pipeline.
stages: [build, test, deploy] # ordered phasesbuild-app:stage: buildimage: node:22-alpine # the job runs in this containerscript:- npm ci- npm run buildartifacts:paths: [dist/] # hand files to later stagesunit-test:stage: testimage: node:22-alpinescript: [npm test]
Stages run in order; jobs in a stage run together
A pipeline is a list of stages that run sequentially — every job in build finishes before any test job starts. Within a stage, jobs run in parallel, so your unit tests, lint, and a scan can all execute at once. A job fails if its script exits non-zero, and a failed job fails its stage, which stops the pipeline. That is the whole control flow: stages gate order, jobs within a stage parallelize.
Each job runs in a container
The image: key sets the container a job runs in, which is how GitLab gives every job a clean, reproducible environment — no "install Node on the runner" drift. This maps directly across tools: it is jobs.<id>.container in GitHub Actions and agent { docker { image } } in Jenkins. The rest of this course is GitLab-centered, but the concepts carry over.