GitLab child/parent pipelines for larger monorepos
AI generated
CI/CD
.yml
GitLab · CI/CD · DevOps
GitLab child/parent pipelines
for larger monorepos

When a monorepo combines several largely independent sub-projects in a single repository, one monolithic .gitlab-ci.yml quickly becomes confusing and inefficient. Parent-child pipelines with the trigger keyword solve this by giving every sub-project its own, independently executable child pipeline that only runs when something in its area has actually changed.

17 min read parent-child pipelines trigger keyword monorepo dynamic pipelines

1. Why a monolithic pipeline fails in a monorepo

A monorepo bundles several sub-projects, such as multiple microservices, a frontend and a backend, or several libraries, into a single git repository, which makes code sharing and atomic commits across project boundaries easier. But this creates a structural problem for the CI/CD pipeline: a single .gitlab-ci.yml containing all jobs for all sub-projects grows longer and more confusing as the number of sub-projects increases, and without targeted control the entire pipeline runs for every commit across all sub-projects, even if only a single line changed in a single microservice.

This behavior wastes not only CI minutes but also slows the feedback loop for developers considerably, because a small fix in one sub-project still has to wait for tests of entirely unrelated sub-projects to finish. As team size and the number of sub-projects grow, a monolithic pipeline also becomes a shared point of change where multiple teams block each other, since every change to the central .gitlab-ci.yml potentially affects all sub-projects. Parent-child pipelines solve exactly this problem by moving responsibility for each sub-pipeline into its own file that can be maintained and triggered independently of the rest.

2. How trigger starts a child pipeline

The trigger keyword defines a special job type that, instead of a script block, points to another .gitlab-ci.yml file and starts it as an independent child pipeline. From the parent pipeline's perspective, the trigger job looks like a normal job with its own status, but internally it orchestrates an entire second pipeline with its own stages, its own jobs and its own pipeline status. The child pipeline runs completely independently from the other jobs in the parent pipeline and can have its own runners, its own variables and its own stage structure, without the two configurations interfering with each other.

Combined with rules and changes, this solves exactly the monorepo problem: one trigger job per sub-project gets a changes condition that only matches when files in the corresponding subdirectory have changed, so a commit that only touches the payment service triggers exclusively the child pipeline for payment, while the child pipelines for all other microservices are skipped entirely. This selective triggering is the central efficiency gain of parent-child pipelines over a monolithic structure.


trigger_payment_service:
  trigger:
    include: services/payment/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - services/payment/**/*

trigger_frontend:
  trigger:
    include: services/frontend/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - services/frontend/**/*

3. strategy: depend and the pipeline status

Without extra configuration, a trigger job is considered successful by default as soon as the child pipeline has been started, regardless of whether the child pipeline itself later fails. This is undesirable for many use cases, because a failed test in the child pipeline then does not automatically mark the parent pipeline as failed. With strategy: depend this behavior changes: the trigger job waits until the child pipeline has fully completed and then adopts its actual success or failure status, so the parent pipeline correctly reflects the real state of all child pipelines.

This setting matters especially when downstream jobs in the parent pipeline depend on several child pipelines, for example a final deployment job that should only run once all affected sub-projects have been tested successfully. Without strategy: depend, that deployment job could incorrectly start even though one of the child pipelines is still running in the background or has even failed. In practice, strategy: depend should therefore be the default for every trigger job whose actual child pipeline success matters for further pipeline logic, and should only be deliberately omitted in rare cases, such as purely informational child pipelines with no blocking effect.

4. Dynamically generated child pipeline YAML as an artifact

Besides child pipeline files that live statically in the repository, GitLab also supports dynamically generated child pipelines, where an upstream job produces a .gitlab-ci.yml file at runtime and provides it as an artifact that then serves as the basis for the trigger job. This is especially valuable in monorepos where the number or structure of sub-projects changes frequently, because the pipeline structure no longer has to be hardcoded, but can instead be derived at runtime from the actual repository state, for example through a script that reads all directories containing a package.json or composer.json and automatically generates one job per sub-project from that.

This technique is often combined with the include: artifact field, which explicitly states that the referenced file is not stored statically in the repository but was produced as an artifact of a previous job. For very large monorepos with dozens of sub-projects, this approach is often the only practical solution, because a manually maintained list of all sub-projects in the parent pipeline quickly becomes outdated and error-prone as new sub-projects are added or old ones removed, whereas a generated pipeline automatically reflects the current state.


generate_pipeline:
  stage: prepare
  script:
    - ./scripts/generate-child-pipeline.sh > generated-pipeline.yml
  artifacts:
    paths:
      - generated-pipeline.yml

trigger_generated:
  stage: trigger
  needs: [generate_pipeline]
  trigger:
    include:
      - artifact: generated-pipeline.yml
        job: generate_pipeline
    strategy: depend

5. Nesting depth and variable forwarding

GitLab allows nesting child pipelines up to a fixed depth, where a parent pipeline can trigger a child pipeline that in turn triggers its own child pipeline. These so-called multi-level pipelines are helpful for very large organizations with hierarchically organized sub-projects, but should be used carefully, because every additional nesting level makes things harder to follow and complicates debugging when a failure occurs deep inside a nested child pipeline and has to be traced back through several levels.

For forwarding variables to a child pipeline, trigger offers the variables sub-keyword, which lets you pass specific values to the child pipeline independent of the globally defined variables of the parent pipeline. Additionally, forward can control whether the parent pipeline's pipeline variables and YAML variables should be automatically passed through to the child pipeline, which is especially important for dynamically generated pipelines to avoid sensitive or project-specific variables unintentionally ending up in child pipelines for other sub-projects.


trigger_service_a:
  trigger:
    include: services/service-a/.gitlab-ci.yml
    strategy: depend
    forward:
      pipeline_variables: true
      yaml_variables: false
  variables:
    SERVICE_NAME: service-a
    DEPLOY_ENV: staging

6. Multi-project pipelines as a related concept

Besides parent-child pipelines within the same repository, trigger also supports triggering pipelines in a completely different GitLab project, so-called multi-project pipelines. Instead of an include file, the project: field specifies the path to another project, so a job in project A starts a pipeline in project B, for example when a central infrastructure repository should automatically trigger a deployment after every successful build of an application repository. Multi-project pipelines are conceptually related to parent-child pipelines, but differ in that the two involved pipelines live in separate projects with their own permissions and their own versioning.

For monorepos, the trigger:include variant with child pipelines in the same repository is usually the better fit, because changes to a sub-project's pipeline and its code end up in a single commit and share the same version history. Multi-project pipelines, on the other hand, are better suited for genuinely separate repositories that should not be merged for organizational or security reasons but still need coordinated pipeline execution, for example between a separate infrastructure-as-code repository and several application repositories.

7. Practical recommendations for the setup

For getting started, a clear directory structure is recommended, where every sub-project maintains its own .gitlab-ci.yml in its own subdirectory, while the parent pipeline at the repository root consists only of a list of trigger jobs with matching changes conditions. This separation makes clear who is responsible for which pipeline logic, and lets teams change their own child pipeline largely independently of other teams, without risking merge conflicts in a shared, giant .gitlab-ci.yml.

It is also important to move shared job definitions, such as linting or security scans needed identically across several sub-projects, into a central, reusable file and include it in every child pipeline via include, instead of duplicating them in every sub-project. This way the structure stays consistent despite multiple independent child pipelines, and changes to shared standards only need to be maintained in one place, which is exactly what separates a maintainable setup from CI configuration that grows chaotically once many sub-projects are involved.

8. Common pitfalls with parent-child pipelines

A common mistake is forgetting strategy: depend and then being puzzled why the parent pipeline shows green despite a failed child pipeline. A second common mistake concerns changes conditions that are too narrow or too broad: if only the exact sub-project directory is listed in changes, but a shared library in a different directory that actually affects the sub-project is changed, the corresponding child pipeline incorrectly does not run even though it should, because GitLab performs no automatic dependency analysis across directory boundaries.

A third pitfall concerns error visibility: since a child pipeline appears in the parent pipeline's default view only as a single job, developers have to actively click into the child pipeline to see failure details, which can initially feel unintuitive, especially for new team members. It is worth briefly explaining, either in the trigger job's description or in team documentation, that a red trigger job means the linked child pipeline needs to be checked, instead of searching for the error directly in the parent log.

9. Conclusion: parent-child pipelines as a scaling tool

Parent-child pipelines with trigger are the central tool for keeping monorepos with multiple sub-projects manageable in GitLab CI, because they enable selective triggering via changes conditions, independent child pipeline configurations, and dynamically generated pipeline structures where needed. Configured correctly with strategy: depend and clearly separated responsibilities per sub-project, this approach scales significantly better than a single monolithic pipeline file, even for monorepos with dozens of sub-projects.

The table below compares the key characteristics of monolithic pipelines, static parent-child pipelines and dynamically generated child pipelines, as a decision aid for your own monorepo structure.

Characteristic Monolithic pipeline Static child pipeline Dynamic child pipeline
Trigger on change always all jobs targeted via changes condition targeted, determined at runtime
Maintenance for new sub-projects central file grows new file plus new trigger job automatic from repository structure
Failure status propagation directly visible correct only with strategy: depend correct only with strategy: depend
Suited for small, simple repos monorepos with a stable structure monorepos with frequently changing structure

Mironsoft

CI/CD pipelines, zero-downtime deployments and release automation

Deployments that run without downtime and without the nail-biting?

We review existing GitLab pipelines for fragile deployment steps and missing safeguards, then build a release process with zero-downtime deployments, automated checks and a rollback you can actually trust in an emergency.

Pipeline Review

Checking an existing .gitlab-ci.yml for fragility, missing stages and security gaps.

Zero-Downtime Deployment

Building symlink releases, health checks and rollback strategies for Magento stores.

CI/CD Automation

Connecting tests, security scans and deployments into one reliable pipeline.

10. Summary

Child/parent pipelines: The essentials at a glance

Core idea

trigger starts an independent child pipeline per sub-project instead of bundling all jobs into one monolithic file.

Selective triggering

changes conditions per trigger job ensure that only actually affected sub-pipelines run.

Critical setting

strategy: depend ensures the parent pipeline adopts the child pipeline's real success or failure status.

For very large monorepos

Dynamically generated child pipeline YAML as an artifact avoids manually maintained, quickly outdated trigger lists.

11. FAQ: Child/parent pipelines: The essentials at a glance

1What is the difference between parent-child pipelines and multi-project pipelines?
Parent-child pipelines trigger child pipelines within the same repository and project, usually via an include file in the repository. Multi-project pipelines instead trigger a pipeline in a completely different GitLab project, via the project field in the trigger keyword.
2Why does my parent pipeline show success despite a failed child pipeline?
Without strategy: depend, a trigger job is already considered successful as soon as the child pipeline has started, regardless of its later outcome. With strategy: depend the trigger job waits for completion and adopts the child pipeline's actual status.
3How do I trigger a child pipeline only when its sub-project has changed?
The trigger job gets a rules condition with a changes clause pointing to the sub-project's directory. Only when files in that path have changed since the comparison point is the child pipeline actually triggered.
4What does a dynamically generated child pipeline mean?
An upstream job generates a .gitlab-ci.yml file at runtime, for example based on the current repository structure, and provides it as an artifact. The trigger job then references that file via include with artifact instead of a static file in the repository.
5How deeply can child pipelines be nested?
GitLab allows nesting child pipelines up to a fixed depth of several levels. In practice this nesting should be used sparingly, since every additional level makes things harder to follow and complicates debugging.
6Are variables automatically forwarded to a child pipeline?
That depends on the forward configuration in the trigger job. pipeline_variables and yaml_variables let you specifically control whether the parent pipeline's variables are automatically passed to the child pipeline, in addition to explicitly set variables.
7Can a child pipeline have its own runners and its own variables?
Yes, a child pipeline is a fully independent pipeline with its own stages, its own jobs, its own runner assignments and its own variables, configured independently of the parent pipeline.
8What happens when a changes condition misses a shared library?
If a shared library lives outside the monitored sub-project directory, GitLab does not automatically detect the dependency. The affected child pipeline then fails to run despite a relevant change, unless the library directory is explicitly added to the changes list.
9Are parent-child pipelines worth it for small repositories?
For small repositories with only one or two sub-projects, the extra overhead is usually not justified. The benefit becomes visible once there are several clearly separable sub-projects, especially when they change at different frequencies.
10How do I see the status of a child pipeline in the GitLab interface?
In the parent pipeline view, the trigger job appears with its own status icon, which is clickable and leads directly to the associated child pipeline with all its own jobs and stages.