Chapter 19Lesson 01~275 minutes

Parent-Child Pipelines, Multi-Project Pipelines, Trigger Tokens, and Pipeline Composition: Concepts, Architecture, and Mental Model

Compose GitLab pipelines without losing source identity, status semantics, authorization boundaries, or control over what configuration and data crosses each edge.

Downstream pipelinesParent-childMulti-projectTrigger jobsCI_JOB_TOKENTrust boundaries

Learning objectives

  • Distinguish parent-child pipelines from multi-project pipelines by project, ref, identity, and trust boundary.
  • Separate a trigger job, CI_JOB_TOKEN API trigger, and pipeline trigger token by authentication and status semantics.
  • Explain default trigger-job status versus strategy: mirror and why strategy: depend is no longer recommended.
  • Use inputs and controlled variable forwarding without accidentally exporting sensitive state.
  • Identify which artifact flows remain tier-gated and keep the mandatory design Free-compatible.
Availability baseline (verified 2026-08-22 against current GitLab 19.3 documentation). Parent-child pipelines, multi-project pipelines, trigger jobs, trigger:strategy: mirror, downstream inputs, pipeline trigger tokens, the pipeline triggers API, CI_JOB_TOKEN cross-project access controls, and the job-token scope API are available on GitLab Free/Premium/Ultimate across GitLab.com, Self-Managed, and Dedicated. The mandatory path uses one disposable Free project and a local child configuration. A second disposable project is optional. Fetching upstream artifacts with needs:pipeline:job or needs:project is currently Premium/Ultimate, so cross-pipeline artifact retrieval is taught with a fixture/read-only extension rather than required for completion.

1. The practical problem: one pipeline eventually stops being one delivery boundary

Chapters 10–18 treated a pipeline as a coherent execution graph inside one project. That model works until a repository grows into a monorepo with independently testable components, or until one product is split across application, infrastructure, packaging, and deployment projects owned by different teams.

The hard problem is not merely “start another pipeline.” The moment one pipeline creates another, you must answer four questions precisely: where does the downstream configuration live, which commit/ref does it represent, whose permissions and secrets apply, and does downstream failure change upstream status?

GitLab calls any pipeline started by another pipeline a downstream pipeline. The two main composition forms have deliberately different boundaries.

2. Mental model: compose configuration first, execution second

Pipeline composition and trust boundaries
flowchart TD
  U[Upstream pipeline
Project A / SHA A] --> T[Trigger job
GitLab control plane]
  T -->|include local/project/template| C[Child pipeline
Project A / same ref + SHA]
  T -->|trigger project B| M[Multi-project pipeline
Project B / selected ref + SHA B]
  J[CI_JOB_TOKEN
job lifetime] -->|API trigger if authorized| M
  K[Pipeline trigger token
long-lived until revoked] -->|Triggers API| Q[Triggered pipeline
source=trigger]
  C --> RC[Child runners / variables / jobs]
  M --> RM[Project B runners / variables / permissions]

The trigger job is a GitLab control-plane object; it does not itself need a runner. Parent-child composition stays in the same project and therefore the child runs under the same project, ref, and commit SHA. Multi-project composition crosses into another project, whose configuration, runner fleet, variables, protected resources, and membership policy become a new trust boundary. A pipeline trigger token is a separate API credential and should not be confused with the YAML trigger keyword.

3. Parent-child pipelines: split configuration without changing project/ref/SHA

A parent pipeline triggers a child pipeline in the same project. Current GitLab guarantees that the child runs under the same project, ref, and commit SHA as the parent. That makes parent-child composition a strong fit for monorepos: one top-level pipeline decides which component pipelines to instantiate while all components still describe one source revision.

Child jobs see CI_PIPELINE_SOURCE=parent_pipeline. Child pipelines are shown from the parent pipeline details rather than as ordinary top-level entries in the project pipeline list. The current nesting limit is two child levels below the parent, and one child trigger can compose up to three configuration files.

component_a:
  trigger:
    include:
      - local: .gitlab/ci/component-a.yml
    strategy: mirror

The include determines which child configuration GitLab compiles. strategy: mirror determines whether the trigger job waits for and mirrors the child pipeline status.

4. Multi-project pipelines: composition crosses ownership boundaries

A multi-project pipeline runs in another GitLab project. The upstream pipeline can choose the target project and ref, and can pass inputs or selected variables, but the downstream project owns its own CI configuration and execution policy.

The user who caused the upstream pipeline to run must have permission to start pipelines in the downstream project. The downstream jobs see CI_PIPELINE_SOURCE=pipeline when they were created by a YAML trigger job or by a CI_JOB_TOKEN call to the pipeline triggers API.

deploy_component:
  trigger:
    project: platform/disposable-deployer
    branch: main
    strategy: mirror

Unlike child pipelines, multi-project pipelines are visible in the downstream project's normal pipeline list and are not constrained by the two-level child nesting limit. That independence is useful, but it increases blast radius: an upstream project may now cause code to execute on another project's runners with another project's variables and target permissions.

5. Trigger jobs are GitLab scheduler objects, not runner jobs

A job with the trigger keyword is called a trigger job. GitLab itself attempts to create the downstream pipeline. The trigger job starts as pending while that creation is attempted, but it does not consume a runner. A trigger job that stays pending unusually long points to downstream creation/permission/configuration problems, not to a missing runner tag.

By default, the trigger job becomes successful as soon as the downstream pipeline is created successfully. The downstream pipeline may fail later without changing that already-successful trigger job.

6. Status coupling: default loose trigger versus strategy: mirror

Mode Trigger job waits? Status meaning Use when
No strategy No Success means “downstream pipeline was created.” Fire-and-observe orchestration where downstream outcome should not block upstream stages.
strategy: mirror Yes Trigger job exactly mirrors downstream pipeline status. Upstream correctness depends on downstream completion.
strategy: depend Yes Legacy dependent behavior with edge-case status differences. Compatibility only; current GitLab recommends mirror instead.

With mirror, later upstream stages wait for the trigger job, and therefore wait for the downstream pipeline. Optional manual jobs downstream do not block completion; blocking manual jobs do. This is status composition, not artifact composition.

7. Three triggering identities that look similar but are not

Mechanism Credential Pipeline source downstream Lifetime / trust
YAML trigger:project GitLab evaluates the upstream user/project permissions pipeline No separately stored trigger secret in YAML; preferred for GitLab-to-GitLab composition when it fits.
CI_JOB_TOKEN + triggers API Ephemeral job token pipeline Exists only while the job runs; cross-project access normally requires target allowlist plus the triggering user’s permissions.
Pipeline trigger token + triggers API Project trigger token trigger Long-lived until revoked; impersonates creator’s project access; appropriate for external integrations when a job token is unavailable.

Authentication does not erase authorization. A valid CI_JOB_TOKEN can still be rejected by a target project that has not allowlisted the source project, or when the pipeline user lacks target permission.

8. CI_JOB_TOKEN: short-lived identity with explicit inbound trust

The job token has the same effective user access level as the user who started the job, but its API surface is deliberately narrower than a personal token. By default, cross-project access requires the source project/group to be present in the target project's CI/CD job-token allowlist and the triggering user to already have the required target permissions.

Current GitLab also supports fine-grained job-token permissions for limiting allowed API endpoint families. Treat the allowlist as permission to attempt authentication, not as membership or role assignment.

9. Pipeline trigger tokens: useful external hook, persistent credential

A pipeline trigger token is created by a Maintainer/Owner and impersonates the creator's project access and permissions. A leaked token can create unscheduled pipelines and may cause jobs to receive variables or deploy authority that the creator could exercise.

Leak response order: revoke the trigger token first. Then create a replacement only if still needed, update the integration securely, and finally remove the leaked value from repositories/logs/history. Deleting the string from Git does not make an already exposed token safe.

The lessons never contain a real trigger token. Syntax examples use obvious non-secret placeholders only.

10. Inputs versus forwarded variables

For downstream configuration parameters, current GitLab recommends inputs when possible. The downstream config declares spec:inputs, and the trigger supplies typed/validated values. This is clearer than a broad bag of environment variables.

# child config
spec:
  inputs:
    channel:
      options: [lab, staging]
      default: lab
---
child_job:
  script:
    - printf 'channel=%s\n' "$[[ inputs.channel ]]"

Variables remain useful, but trigger:forward can elevate forwarded values to trigger-variable precedence. Forwarding pipeline variables is off by default; YAML variables are forwarded by default. Forwarded values do not automatically forward again through another downstream level unless the nested trigger also opts in.

11. Do not forward masked secrets as ordinary multi-project variables

GitLab explicitly warns against passing masked variables to a multi-project pipeline through ordinary variable inheritance: the masking configuration is not carried to the downstream project, so the value could appear unmasked in logs. Prefer a downstream project's own scoped secret, an external secret manager/OIDC flow, or another least-privilege design rather than moving a long-lived secret across project boundaries.

12. Status flow and artifact flow are separate

strategy: mirror does not make parent artifacts magically appear in a child. Current GitLab's upstream-artifact retrieval with needs:pipeline:job (parent-child) or needs:project (multi-project) is Premium/Ultimate. The mandatory Free path therefore proves composition with inputs, metadata, pipeline status, and independently produced child outputs.

When the paid feature is available, artifact identity still requires explicit project/pipeline/job/ref selection and permissions. For merge request pipelines, the correct upstream ref may be CI_MERGE_REQUEST_REF_PATH, not the source branch name.

13. Read-only inspection before changing composition

PROJECT_ID="12345678"
PARENT_PIPELINE_ID="9001"

# Parent pipeline identity.
glab api "projects/$PROJECT_ID/pipelines/$PARENT_PIPELINE_ID"   --jq '{id,project_id,ref,sha,status,source,user:.user.username}'

# Current GitLab 19.2+ route for trigger jobs (older /bridges route is deprecated).
glab api "projects/$PROJECT_ID/pipelines/$PARENT_PIPELINE_ID/trigger_jobs"   --jq '.[] | {id,name,status,downstream_pipeline:(.downstream_pipeline|{id,project_id,ref,sha,status})}'

# Child pipelines can be queried by source explicitly.
glab api "projects/$PROJECT_ID/pipelines?source=parent_pipeline" --paginate   --jq '.[] | {id,ref,sha,status,source}'

Do not query or print trigger-token values, CI_JOB_TOKEN, all job variables, or full untrusted payloads. The control-plane evidence above is enough to prove identity and status relationships.

14. Current structural limits are architecture signals

The current default pipeline hierarchy can contain up to 1000 downstream pipelines, and parent-child nesting is capped at two child levels. These are not performance targets. If a design approaches them, ask whether the decomposition is expressing real ownership/dependency boundaries or merely multiplying orchestration objects.

15. DevOps connection: composition creates transitive trust

A trigger edge is also a trust edge. It can cause a different configuration to compile, a different runner to execute code, a different variable set to appear, and a different deployment identity to act. Production pipeline architecture should therefore document each edge with project/ref, trigger mechanism, status strategy, allowed inputs, token policy, secret boundary, and owner.

Knowledge check

What does a parent-child pipeline share with its parent?

What does a default trigger-job success prove?

Which status strategy is currently recommended when upstream must wait for downstream outcome?

Does adding Project A to Project B’s job-token allowlist grant Project A users a role in B?

Why are typed inputs preferable to broad forwarded variables for configuration parameters?

Does strategy: mirror transfer artifacts from the parent?

Summary

Parent-child pipelines decompose one project/ref/SHA; multi-project pipelines cross project ownership and execution boundaries. Trigger jobs create downstream pipelines without a runner. Default trigger semantics are loosely coupled, while strategy: mirror couples status. Use typed inputs for configuration, restrict variable forwarding, prefer short-lived job-token flows inside GitLab, and treat trigger tokens as revocable persistent credentials.

Official references

Next lesson

Build and inspect composition safely

Lesson 2 creates a Free-compatible parent-child pipeline, verifies source/SHA/status through current APIs, then offers a second disposable-project extension using trigger:project and a controlled job-token authorization drill.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.