GitLab CI/CD Keywords and Usage | Complete Reference Guide
GitLab CI/CD provides a rich set of keywords and conditions to control pipeline execution. This guide covers essential keywords, stage conditions, and usage patterns for effective pipeline management.
๐๏ธ Build Keywords
Section titled โ๐๏ธ Build KeywordsโThe core keyword that defines what commands to execute in a job.
build_job:  script:    - echo "Building application"    - npm install    - npm run buildbefore_script and after_script
Section titled โbefore_script and after_scriptโExecute commands before and after the main script.
build_job:  before_script:    - echo "Preparing environment"    - export NODE_ENV=production  script:    - npm run build  after_script:    - echo "Cleaning up"    - rm -rf temp/Specify the Docker image to use for the job.
build_job:  image: node:18-alpine  script:    - npm run build
build_with_specific_image:  image:    name: node:18    entrypoint: [""]  script:    - npm run buildservices
Section titled โservicesโAdditional Docker containers to run alongside the job.
test_with_database:  image: node:18  services:    - postgres:13    - redis:6-alpine  variables:    POSTGRES_DB: testdb    POSTGRES_USER: testuser    POSTGRES_PASSWORD: testpass  script:    - npm run test:integration๐ญ Stage Keywords
Section titled โ๐ญ Stage KeywordsโDefine the order of stages in the pipeline.
stages:  - prepare  - build  - test  - security  - deploy  - cleanupAssign a job to a specific stage.
prepare_env:  stage: prepare  script:    - echo "Preparing environment"
build_app:  stage: build  script:    - echo "Building application"
test_app:  stage: test  script:    - echo "Testing application"Hidden Jobs and Templates
Section titled โHidden Jobs and TemplatesโCreate reusable job templates using .job_name syntax.
.deploy_template: &deploy  image: alpine:latest  before_script:    - apk add --no-cache curl  script:    - echo "Deploying to $ENVIRONMENT"
deploy_staging:  <<: *deploy  stage: deploy  variables:    ENVIRONMENT: staging  only:    - develop
deploy_production:  <<: *deploy  stage: deploy  variables:    ENVIRONMENT: production  only:    - mainโ๏ธ Run Conditions - when Keyword
Section titled โโ๏ธ Run Conditions - when Keywordโon_success (Default)
Section titled โon_success (Default)โJob runs only when all previous jobs succeed.
deploy_job:  stage: deploy  when: on_success  # This is the default  script:    - echo "Deploying after successful build and test"Job runs regardless of previous job status.
cleanup_job:  stage: cleanup  when: always  script:    - echo "Cleaning up resources"    - rm -rf temp/    - docker system prune -fJob never runs automatically (must be triggered manually).
emergency_rollback:  stage: deploy  when: never  script:    - echo "Rolling back to previous version"    - kubectl rollout undo deployment/myappon_failure
Section titled โon_failureโJob runs only when at least one previous job fails.
notify_failure:  stage: notify  when: on_failure  script:    - echo "Build failed, sending notification"    - curl -X POST -H 'Content-type: application/json' --data '{"text":"Build failed!"}' $SLACK_WEBHOOKJob requires manual intervention to start.
deploy_production:  stage: deploy  when: manual  script:    - echo "Deploying to production"  environment:    name: productiondelayed
Section titled โdelayedโJob starts after a specified delay.
deploy_with_delay:  stage: deploy  when: delayed  start_in: 30 minutes  script:    - echo "Deploying after delay"๐ฏ Job Control Keywords
Section titled โ๐ฏ Job Control Keywordsโonly and except
Section titled โonly and exceptโControl when jobs run based on branches, tags, or other conditions.
# Using onlydeploy_production:  script:    - echo "Deploying to production"  only:    - main    - /^release\/.*$/
# Using excepttest_job:  script:    - npm test  except:    - schedules    - triggers
# Complex conditionscomplex_job:  script:    - echo "Complex conditions"  only:    refs:      - main      - develop    variables:      - $DEPLOY_ENABLED == "true"    changes:      - src/**/*      - package.jsonMore powerful alternative to only and except.
# Basic rulesdeploy_job:  script:    - echo "Deploying"  rules:    - if: '$CI_COMMIT_BRANCH == "main"'    - if: '$CI_COMMIT_TAG'
# Complex rules with when conditionstest_job:  script:    - npm test  rules:    - if: '$CI_COMMIT_BRANCH == "main"'      when: always    - if: '$CI_COMMIT_BRANCH == "develop"'      when: manual    - changes:        - "src/**/*"      when: on_success    - when: never
# Rules with variablesconditional_deploy:  script:    - echo "Conditional deployment"  rules:    - if: '$DEPLOY_TO_STAGING == "true"'      variables:        ENVIRONMENT: staging    - if: '$DEPLOY_TO_PRODUCTION == "true"'      variables:        ENVIRONMENT: production      when: manualallow_failure
Section titled โallow_failureโAllow job to fail without affecting pipeline status.
experimental_test:  script:    - npm run experimental-tests  allow_failure: true
optional_security_scan:  script:    - security-scan  allow_failure:    exit_codes:      - 2      - 3๐ฆ Artifacts and Dependencies
Section titled โ๐ฆ Artifacts and Dependenciesโartifacts
Section titled โartifactsโSave files and directories after job completion.
build_job:  script:    - npm run build  artifacts:    name: "build-$CI_COMMIT_SHORT_SHA"    paths:      - dist/      - build/    exclude:      - "**/*.tmp"      - "dist/debug/"    expire_in: 1 week    when: on_success    reports:      junit: test-results.xml      coverage: coverage.xmldependencies
Section titled โdependenciesโControl which artifacts are downloaded.
test_job:  dependencies:    - build_job  script:    - npm test
deploy_job:  dependencies:    - build_job  script:    - deploy.shAdvanced job dependencies for parallel execution.
build_backend:  stage: build  script:    - build-backend.sh
build_frontend:  stage: build  script:    - build-frontend.sh
test_integration:  stage: test  needs:    - build_backend    - build_frontend  script:    - integration-tests.sh๐ Environment and Variables
Section titled โ๐ Environment and Variablesโenvironment
Section titled โenvironmentโDeploy to specific environments with tracking.
deploy_staging:  script:    - deploy.sh staging  environment:    name: staging    url: https://staging.myapp.com    on_stop: stop_staging
deploy_production:  script:    - deploy.sh production  environment:    name: production    url: https://myapp.com    auto_stop_in: 1 week
stop_staging:  script:    - stop-environment.sh staging  environment:    name: staging    action: stop  when: manualvariables
Section titled โvariablesโDefine job-specific variables.
# Global variablesvariables:  GLOBAL_VAR: "global_value"  NODE_VERSION: "18"
# Job-specific variablesbuild_job:  variables:    BUILD_ENV: production    OPTIMIZE: "true"  script:    - echo "Building with $BUILD_ENV environment"    - echo "Optimization: $OPTIMIZE"
# Conditional variables with rulesdeploy_job:  script:    - deploy.sh  rules:    - if: '$CI_COMMIT_BRANCH == "main"'      variables:        ENVIRONMENT: production    - if: '$CI_COMMIT_BRANCH == "develop"'      variables:        ENVIRONMENT: staging๐ Parallel and Matrix Jobs
Section titled โ๐ Parallel and Matrix Jobsโparallel
Section titled โparallelโRun multiple instances of the same job.
test_parallel:  script:    - echo "Running test chunk $CI_NODE_INDEX of $CI_NODE_TOTAL"    - npm run test:chunk:$CI_NODE_INDEX  parallel: 5
# Matrix jobstest_matrix:  script:    - npm run test  parallel:    matrix:      - NODE_VERSION: ["16", "18", "20"]        OS: ["ubuntu", "alpine"]๐ Scheduling and Triggers
Section titled โ๐ Scheduling and Triggersโworkflow
Section titled โworkflowโControl when pipelines run.
workflow:  rules:    - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'      when: never    - if: '$CI_COMMIT_BRANCH'
# Scheduled pipelinesscheduled_cleanup:  script:    - cleanup-old-artifacts.sh  only:    - schedulestrigger
Section titled โtriggerโTrigger downstream pipelines.
trigger_downstream:  trigger:    project: mygroup/downstream-project    branch: main    strategy: depend
# Multi-project pipelinedeploy_microservices:  trigger:    include:      - project: mygroup/user-service        file: .gitlab-ci.yml      - project: mygroup/order-service        file: .gitlab-ci.yml๐ท๏ธ Tags and Resources
Section titled โ๐ท๏ธ Tags and ResourcesโSpecify which runners to use.
build_gpu:  tags:    - gpu    - linux  script:    - train-model.py
deploy_kubernetes:  tags:    - kubernetes    - production  script:    - kubectl apply -f deployment.yamlresource_group
Section titled โresource_groupโEnsure only one job runs at a time for a resource.
deploy_production:  resource_group: production  script:    - deploy-to-production.sh
migrate_database:  resource_group: production  script:    - migrate-database.sh๐ Security and Cache
Section titled โ๐ Security and CacheโCache dependencies between jobs.
build_job:  cache:    key:      files:        - package-lock.json        - yarn.lock    paths:      - node_modules/      - .yarn-cache/    policy: pull-push  script:    - npm ci    - npm run build
test_job:  cache:    key:      files:        - package-lock.json    paths:      - node_modules/    policy: pull  script:    - npm testid_tokens
Section titled โid_tokensโGenerate OIDC tokens for secure authentication.
deploy_aws:  id_tokens:    AWS_TOKEN:      aud: https://aws.amazon.com  script:    - aws sts assume-role-with-web-identity --role-arn $AWS_ROLE_ARN --role-session-name gitlab-ci --web-identity-token $AWS_TOKEN๐ Advanced Usage Patterns
Section titled โ๐ Advanced Usage PatternsโConditional Job Execution with Complex Logic
Section titled โConditional Job Execution with Complex Logicโsmart_deploy:  script:    - |      if [ "$CI_COMMIT_BRANCH" = "main" ]; then        echo "Deploying to production"        deploy-production.sh      elif [ "$CI_COMMIT_BRANCH" = "develop" ]; then        echo "Deploying to staging"        deploy-staging.sh      else        echo "Feature branch deployment"        deploy-preview.sh      fi  rules:    - if: '$CI_COMMIT_BRANCH =~ /^(main|develop|feature\/.*)$/'      when: on_success    - when: neverDynamic Pipeline Generation
Section titled โDynamic Pipeline Generationโgenerate_tests:  stage: prepare  script:    - |      for service in $(ls services/); do        cat >> dynamic_jobs.yml << EOF      test_${service}:        stage: test        script:          - cd services/${service}          - npm test      EOF      done  artifacts:    paths:      - dynamic_jobs.yml
include:  - local: dynamic_jobs.ymlPipeline Templates with Includes
Section titled โPipeline Templates with Includesโ# In .gitlab-ci-template.yml.deploy_template:  image: alpine:latest  before_script:    - apk add --no-cache curl kubectl  script:    - kubectl apply -f k8s/  environment:    name: $ENVIRONMENT    url: $DEPLOYMENT_URL
# In main .gitlab-ci.ymlinclude:  - local: '.gitlab-ci-template.yml'
deploy_staging:  extends: .deploy_template  variables:    ENVIRONMENT: staging    DEPLOYMENT_URL: https://staging.myapp.com  only:    - develop
deploy_production:  extends: .deploy_template  variables:    ENVIRONMENT: production    DEPLOYMENT_URL: https://myapp.com  when: manual  only:    - mainThis comprehensive guide covers the essential GitLab CI/CD keywords and usage patterns for building robust and flexible pipelines.