GitLab CI/CD: Downstream (Parent-Child) Pipeline in Same Project
This chapter explores GitLab CI/CD Downstream Pipelines, specifically focusing on Parent-Child Pipelines within the same repository. We examine why they are needed, how to structure them using specialized trigger jobs, and how to scale multi-environment deployments (Dev, QA, Stage, Production) cleanly without cluttering your main pipeline dashboard.
1. Why Do We Need Parent-Child Pipelines? (The Problem Space)
In a standard, linear GitLab CI/CD pipeline, every stage (such as compile, test, package, and deploy) is defined inside a single monolithic .gitlab-ci.yml file.
- The Clutter Problem: As applications grow, adding multiple environments (Dev, QA, Stage, Production) alongside database migrations, health checks, and pre/post-deployment steps introduces dozens of jobs. Putting everything in one file turns the pipeline graph into an overwhelming, cluttered wall of boxes.
- The Complexity Wall: Managing conditional execution, parallel matrices, and complex deployment workflows in a single file becomes error-prone and hard to maintain.
- The Solution: Split your pipeline hierarchically. The Parent Pipeline handles fast, core building blocks (compile, test, package), while Child Pipelines handle specialized, sequential workflows (like multi-stage deployments) triggered dynamically on demand.
2. Core Mental Model & Real-Life Analogy
Real-Life Analogy: The General Contractor and Subcontractors
Think of building a house. The Parent Pipeline is the general contractor who oversees the main architectural milestones: laying the foundation, framing, and roofing (Compiling, Testing, Packaging).
Once the house is packaged and ready, the general contractor hands off specific, multi-step sub-contracts to specialized teams—like the electrical crew, plumbing crew, and interior finishing crew (Child Pipelines). The electrical crew runs their own internal sequence of checks (wire pulling, fixture installation, voltage testing) without cluttering the general contractor's primary milestone tracker.
3. Anatomy of a Parent Pipeline with a Trigger Job
To kick off a child pipeline from a parent pipeline, GitLab uses a special type of job configured with the trigger keyword instead of the standard script keyword.
Mutual Exclusivity Rule: script vs. trigger
A job in GitLab CI/CD cannot contain both a script section and a trigger section.
- Standard jobs require
scriptto execute shell commands. - Trigger jobs initiate downstream/child pipelines and will throw a YAML parsing error if
scriptis defined alongsidetrigger.
# Inside .gitlab-ci.yml (Parent Pipeline)
stages:
- compile
- test
- package
- deploy
# ... compile, test, package stages execute here ...
dev_environment_deployment:
stage: deploy
trigger:
include:
- local: 'deploy-dev.yml'
strategy: depend
forward:
yaml_variables: true
pipeline_variables: true
variables:
ENVIRONMENT_HOST_NAME: "dev-server.internal.net"
4. Connecting Parent to Child: The include: local Configuration
When working within the same project, you use the local keyword under include to point GitLab to the YAML file living in your repository's root directory that defines the child pipeline's structure.
Key Keywords Explained:
trigger: Identifies this job as a downstream pipeline launcher.include: local: Points to a configuration file residing in the exact same Git repository at the specified path.strategy: depend: Ensures that if any job inside the child pipeline fails, the parent pipeline job fails as well. Without this, a child pipeline failure might be ignored by the parent, marking the parent job as green.forward: Controls variable inheritance. Settingyaml_variables: trueandpipeline_variables: truepasses variables defined in the parent context directly into the child pipeline.
5. Designing the Child Pipeline Configuration (deploy-dev.yml)
The child pipeline is an independent pipeline with its own sequence of stages and jobs. Below is an example of what the child deployment configuration looks like:
# deploy-dev.yml (Child Pipeline Configuration)
stages:
- pre-deploy
- deploy
- db-migration
- post-deploy
- health-check
stop_service_job:
stage: pre-deploy
script:
echo "Stopping existing service on host: $ENVIRONMENT_HOST_NAME"
# commands to stop application server
deploy_application_job:
stage: deploy
script:
echo "Copying archive file to $ENVIRONMENT_HOST_NAME"
# commands to copy .jar or build artifacts
run_db_migrations:
stage: db-migration
script:
echo "Executing database migration scripts..."
post_deploy_cleanup:
stage: post-deploy
script:
echo "Cleaning up temporary files..."
health_check_job:
stage: health-check
script:
echo "Verifying application health endpoint..."
# curl -f http://$ENVIRONMENT_HOST_NAME/health
6. Scaling to Multi-Environment Deployments (Dev -> QA -> Stage -> Prod)
You can scale this pattern to handle multiple target environments by defining multiple trigger jobs in the parent pipeline, passing unique environment variables and hostnames to each child execution.
# Parent Pipeline Scaled for Multiple Environments
stages:
- compile
- test
- package
- deploy
dev_deploy:
stage: deploy
trigger:
include:
- local: 'deploy-dev.yml'
strategy: depend
variables:
ENVIRONMENT_HOST_NAME: "dev-server.internal.net"
qa_deploy:
stage: deploy
needs: [dev_deploy]
trigger:
include:
- local: 'deploy-dev.yml'
strategy: depend
variables:
ENVIRONMENT_HOST_NAME: "qa-server.internal.net"
stage_deploy:
stage: deploy
needs: [qa_deploy]
trigger:
include:
- local: 'deploy-dev.yml'
strategy: depend
variables:
ENVIRONMENT_HOST_NAME: "stage-server.internal.net"
prod_deploy:
stage: deploy
needs: [stage_deploy]
trigger:
include:
- local: 'deploy-dev.yml'
strategy: depend
variables:
ENVIRONMENT_HOST_NAME: "prod-server.internal.net"
7. Pipeline Execution Flow Walkthrough
Here is how data and execution flow across parent and child boundaries when a commit is pushed:
8. Real-World Production Considerations & Best Practices
- Automatic vs. Manual Triggers: While automated cascading pipelines (
Dev -> QA -> Stage -> Prod) are useful for continuous delivery, enterprise environments typically require manual gates. Addingwhen: manualto environment triggers prevents untested code from automatically pushing to production without human sign-off. - Pipeline Visibility: Parent and child pipelines maintain separate Pipeline IDs in GitLab. If a child pipeline fails, you can click directly into the child pipeline ID from the parent UI to inspect the exact failure logs without wading through build logs.
- Variable Isolation: Always pass environment-specific parameters (like
ENVIRONMENT_HOST_NAME, database connection strings, or API tokens) via thevariablesblock inside the parent trigger job to ensure environment security and separation of concerns.
Summary and Key Takeaways
- Definition: Parent-child pipelines allow one GitLab CI/CD pipeline to dynamically trigger and manage another independent pipeline.
- Same-Project Scope: Using
include: locallets you reference child configuration YAML files stored locally within the same repository. - The
triggerKeyword: Trigger jobs are special; they cannot containscriptblocks and must exclusively usetriggerdirectives. - Failure Propagation: Utilizing
strategy: dependensures that any failure in the child deployment pipeline correctly fails the parent pipeline. - Variable Forwarding: You can pass parent variables and global pipeline variables into child pipelines using
forward: { yaml_variables: true, pipeline_variables: true }or pass custom job-level variables. - Dashboard Cleanliness: Breaking complex multi-environment deployments into child pipelines keeps your GitLab UI scannable, modular, and easy to audit.