These keywords are fundamental for defining the structure and execution order of your CI/CD pipeline.
stages(Global): A top-level keyword that defines all possible stages in your pipeline and their order of execution.stage(Job-level): A keyword used within a job definition to assign that job to one of the globally defined stages.
Example .gitlab-ci.yml with stages and stage:
YAML
# .gitlab-ci.yml
# 1. Global 'stages' definition:
# Defines the sequence of stages in the pipeline.
# Jobs in earlier stages must complete successfully before jobs in later stages can start.
stages:
- build_assets # First stage
- run_tests # Second stage
- deploy_app # Third stage
default:
image: alpine:latest # Using a lightweight default image for our jobs
# --- Jobs for the 'build_assets' stage ---
compile_code:
stage: build_assets # 2. Assigning this job to the 'build_assets' stage
script:
- echo "--- Compiling Code (Stage: build_assets) ---"
- sleep 5 # Simulate work
- echo "Code compilation complete."
package_application:
stage: build_assets # This job is also in the 'build_assets' stage
script:
- echo "--- Packaging Application (Stage: build_assets) ---"
- sleep 7 # Simulate work
- echo "Application packaging complete."
# --- Jobs for the 'run_tests' stage ---
unit_tests:
stage: run_tests # Assigning this job to the 'run_tests' stage
script:
- echo "--- Running Unit Tests (Stage: run_tests) ---"
- sleep 10 # Simulate work
- echo "Unit tests PASSED."
integration_tests:
stage: run_tests # This job is also in the 'run_tests' stage
script:
- echo "--- Running Integration Tests (Stage: run_tests) ---"
- sleep 12 # Simulate work
- echo "Integration tests PASSED."
# - exit 1 # Uncomment this line to simulate a test failure and see subsequent stages not run
# --- Job for the 'deploy_app' stage ---
deploy_to_production:
stage: deploy_app # Assigning this job to the 'deploy_app' stage
script:
- echo "--- Deploying to Production (Stage: deploy_app) ---"
- sleep 8 # Simulate work
- echo "Deployment to production successful!"
when: on_success # Default, but good to be explicit for deploy jobs
Code language: PHP (php)
Explanation:
- Global
stagesDefinition:stages:at the top level of your.gitlab-ci.ymlfile lists all the stages your pipeline will have.- Order Matters: The order in which you list the stages here dictates the sequence of execution for the entire pipeline.
- In this example:
build_assetswill run first, thenrun_tests, and finallydeploy_app.
- In this example:
- If this global
stageslist is not defined, GitLab CI defaults to a set of predefined stages (build,test,deploy), and if a job doesn’t specify astage, it defaults totest. However, it’s a strong best practice to always define yourstagesexplicitly for clarity and control.
- Job-Level
stage:Keyword:- Inside each job definition (e.g.,
compile_code,unit_tests), thestage:keyword assigns that job to one of the stages previously listed in the globalstagesdefinition. - A job must belong to a stage that is defined in the global
stageslist. If you assign a job to a stage not listed globally, you’ll get a linting error.
- Inside each job definition (e.g.,
- Execution Flow:
- Within a Stage (Parallel Execution):
- All jobs belonging to the same stage can run in parallel if enough GitLab Runners are available.
- For example,
compile_codeandpackage_applicationare both in thebuild_assetsstage. They can start simultaneously. - Similarly,
unit_testsandintegration_tests(both inrun_tests) can run in parallel.
- Between Stages (Sequential Execution):
- A stage will only start after all jobs in the preceding stage have completed successfully.
- The
run_testsstage (containingunit_testsandintegration_tests) will only begin after bothcompile_codeANDpackage_applicationfrom thebuild_assetsstage have finished successfully. - The
deploy_appstage (withdeploy_to_production) will only begin after bothunit_testsANDintegration_testsfrom therun_testsstage have finished successfully.
- Job Failure Impact:
- If any job in a stage fails, by default:
- No new jobs will start in that stage (though currently running parallel jobs in the same stage will continue unless
interruptibleis used or they depend on the failed job vianeeds). - All subsequent stages will be skipped, and the pipeline will be marked as failed.
- In the example, if
integration_testsfails (e.g., by uncommentingexit 1), thedeploy_to_productionjob in thedeploy_appstage will not run.
- No new jobs will start in that stage (though currently running parallel jobs in the same stage will continue unless
- If any job in a stage fails, by default:
- Within a Stage (Parallel Execution):
default:Section:default: image: alpine:latestis just setting a default Docker image for all jobs to keep the example concise. It’s not directly related to staging but is good practice.
Benefits of Using Stages:
- Control Flow: Clearly defines the order of operations in your CI/CD process.
- Logical Grouping: Groups related tasks together (e.g., all build activities, all testing activities).
- Efficiency: Allows for parallel execution of independent tasks within the same phase of your pipeline.
- Failure Management: Prevents later stages (like deployment) from running if earlier critical stages (like testing) fail.
- Readability: Makes the pipeline structure easier to understand.
By defining stages and assigning jobs to them using stage:, you create a structured, ordered, and manageable workflow for your GitLab CI/CD pipelines.