Stage
A CI/CD stage is a logical grouping of related jobs within a pipeline representing one phase of delivery — such as Build, Test, Scan, or Deploy. Stages run sequentially and a failed stage blocks all subsequent stages from running.
Understanding CI/CD Stages
What Is a Stage in Simple Terms
A stage is one chapter in the pipeline story. Build is chapter one. Test is chapter two. If chapter two fails, you do not proceed to chapter three. This gate behaviour is the entire point of stages: a failed test should prevent a deployment, not just be noted and ignored.
Think of stages as quality checkpoints on an assembly line. A car does not move to the paint shop until the body shop confirms the frame is correct. Code does not move to deployment until the test stage confirms it works.
How It Works
+------------------------------------------+| Stage 1: Build || Jobs: compile, docker-build, push-image |+------------------------------------------+ | all jobs pass? / \ yes no | | v v+------------------+ +------------------+| Stage 2: Test | | PIPELINE BLOCKED || Jobs: unit-test | | Deploy blocked || integration-test | | Notify engineer || coverage-check | +------------------++------------------+ | all jobs pass? | v+------------------------------------------+| Stage 3: Deploy || Jobs: deploy-staging, smoke-test |+------------------------------------------+Stage definition in GitHub Actions (jobs with needs):
jobs: build: ## Stage 1 runs-on: ubuntu-latest steps: - run: docker build . unit-test: ## Stage 2 (parallel with lint) needs: build runs-on: ubuntu-latest steps: - run: npm test lint: ## Stage 2 (parallel with unit-test) needs: build runs-on: ubuntu-latest steps: - run: npm run lint security-scan: ## Stage 3 (after both Stage 2 jobs) needs: [unit-test, lint] runs-on: ubuntu-latest steps: - run: trivy image payment-api:${{ github.sha }} deploy: ## Stage 4 needs: security-scan runs-on: ubuntu-latest steps: - run: ./deploy.shStage definition in GitLab CI:
stages: - build - test - scan - deploy build-image: stage: build script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . unit-tests: stage: test script: - npm test trivy-scan: stage: scan script: - trivy image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA deploy-staging: stage: deploy script: - ./deploy.sh stagingPractical Commands
## GitHub Actions -- rerun a failed stage onlygh run rerun RUN_ID --failed ## GitLab -- retry a specific failed jobglab ci retry JOB_ID ## Jenkins -- replay a failed build## In Jenkinsfile: use retry(3) step for transient failures## stage('Test') {## retry(3) { sh 'npm test' }## }Troubleshooting
| Symptom | Check | What to Look For |
|---|---|---|
| Stage skipped unexpectedly | Review job conditions | if/when conditions blocking execution |
| Stage hangs with no output | Check timeout settings | Job timeout too short or process waiting |
| Parallel jobs causing conflicts | Check shared state | Jobs writing to same files or ports |
TipName stages after their purpose, not their tools. Call it Test not jest. Call it Scan not trivy. Tools change; stages do not. A pipeline named after tools requires renaming when you switch from Jest to Vitest.
RememberEvery stage is a gate. A gate only has value if it actually blocks. If your Test stage is allowed to fail without blocking deployment, it is not a gate — it is decoration. Every stage must be configured to block the pipeline on failure.
SecurityStages that deploy to production must require explicit human approval via environment protection rules. An automated pipeline that deploys to production without a gate is a single point of failure — a bug in CI configuration can push broken code to production without anyone reviewing it.
Common MistakeCreating a single monolithic stage that runs build, test, scan, and deploy all at once. When that stage fails, you cannot tell which part failed without reading all the logs. Split concerns into distinct named stages so failures are immediately visible and targeted retries are possible.
Frequently Asked Questions
What's the difference between a stage and a job in a CI/CD pipeline?
A stage is a phase like Build, Test, or Deploy; a job is the actual unit of work that runs within a stage — a stage can contain multiple jobs that run in parallel with each other, while stages themselves typically run sequentially, one after another. This two-level structure (used in GitLab CI, Azure Pipelines, and similar) lets you parallelize, say, unit tests and linting within the Test stage while still guaranteeing Test fully completes before Deploy starts.
What's a common mistake when structuring pipeline stages?
Cramming too much into one stage so a single flaky test blocks an unrelated deploy, or the opposite — over-splitting into so many sequential stages that pipeline runtime balloons because each stage waits for the previous one to fully finish even when the work could run in parallel. A good rule of thumb: stages should reflect a genuine gate you want (don't deploy if tests fail), not just an organizational label.