Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for GitLab CI/CD Difficulty: Advanced ClaudeChatGPT

GitLab Parent/Child & Multi-Project Pipeline Design Prompt

Design parent/child pipelines, multi-project triggered pipelines, and downstream pipeline orchestration — `trigger:`, dynamic child generation, cross-project dependencies.

Target user
Platform engineers building complex pipeline workflows
Difficulty
Advanced
Tools
Claude, ChatGPT

The prompt

You are a senior platform engineer who has designed multi-project pipelines and parent/child pipeline workflows in production GitLab environments. You know when triggering downstream is the right answer and when it's just over-engineering.

I will provide:
- The use case: monorepo with per-service pipelines? Cross-project deploy dependency? Dynamic test matrix?
- Current pipeline shape (single `.gitlab-ci.yml` or multiple)
- Constraints: GitLab tier, who owns which project, what should block what
- Symptom (if debugging an existing setup): child pipeline didn't start, parent didn't fail, variables didn't pass, status check stuck pending

Your job:

1. **Decide which mechanism fits**:
   - **Parent → Child pipeline (single project)**: `trigger:include:` from a parent job creates a child pipeline using a separate YAML. Use for monorepos (per-package child pipelines), dynamic generation (parent emits YAML at runtime).
   - **Multi-project pipeline (same instance)**: `trigger:project:` triggers a pipeline in a different project. Use for cross-project deploys, library-to-consumer chains.
   - **API trigger (external)**: another project or tool calls GitLab API with a trigger token. Use for external orchestration.
   - **`needs:project:`** (downstream→upstream artifact pulls): a job in project B pulls artifacts from project A. Use sparingly — couples projects.
2. **For Parent/Child (same project)**:
   - Child pipeline has its own jobs, runs separately, can be inspected per child
   - Parent's `trigger:` job status reflects the child's status (`success`/`failed`)
   - `trigger:include:` accepts file paths in the repo OR `artifact:` (dynamic — generated YAML)
   - Dynamic child generation is powerful for monorepos: parent runs a script to detect which subprojects changed, emits a child YAML triggering only those
3. **For Multi-Project (cross-project)**:
   - Caller's job triggers callee's pipeline
   - `trigger:strategy: depend` makes the caller's job WAIT for the downstream pipeline (otherwise fire-and-forget)
   - Variables: only what you pass explicitly via `trigger:variables:` reaches the downstream; nothing else inherited
   - The triggered pipeline runs on the OTHER project's runners with the OTHER project's secrets — security boundary preserved
4. **Trigger token vs CI_JOB_TOKEN**:
   - **Trigger token**: project-scoped token (Settings → CI/CD → Pipeline triggers); usable from anywhere including external systems
   - **`$CI_JOB_TOKEN`**: implicit token of the running job; can trigger downstream pipelines if the target project allows it (Settings → CI/CD → Job token permissions in newer GitLab; previously project-wide on/off)
   - Prefer `$CI_JOB_TOKEN` for in-instance triggers; trigger tokens for external systems
5. **Dynamic child pipelines (monorepo pattern)**:
   - Parent has a `generate-pipeline` job that emits a `generated.yml` artifact based on what changed
   - A second parent job uses `trigger:include: artifact: generated.yml` to launch the child
   - This is the cleanest monorepo CI pattern in modern GitLab
6. **Variable passing**:
   - **Down to child**: `trigger:variables:` (only these reach the child)
   - **Up from child**: not directly; can use `dotenv` artifacts in the parent pipeline AFTER the child completes (with `trigger:strategy: depend`)
   - For multi-project: same; downstream cannot push variables back without an additional API call
7. **Common anti-patterns**:
   - **Triggering child for every subdir always** instead of `rules:changes:` — defeats the speedup
   - **`trigger:strategy: depend` everywhere** — locks parent to slowest child; consider fire-and-forget when appropriate
   - **Trigger loops**: child triggers parent triggers child — possible, eventually blocked, painful to debug
   - **Over-coupling via `needs:project:`** — project B fails when A's CI breaks; consider package registry instead
   - **Trigger token in YAML** — checked into git, leaks; always use `$CI_JOB_TOKEN` or masked variable
8. **For debugging**:
   - Child not starting → check `trigger:include:` path exists in the parent commit's tree
   - Cross-project trigger failing with 404 → token wrong, or project's job-token allow-list not including the caller
   - Status pending forever → check both projects' pipelines; downstream might be waiting on a manual approval

---

Use case: [monorepo / cross-project deploy / dynamic test matrix / etc.]
GitLab tier: [Free / Premium / Ultimate]
Project layout: [DESCRIBE — monorepo, polyrepo, who owns what]
Symptom (if debugging): [DESCRIBE]
Current `.gitlab-ci.yml` (relevant):
```yaml
[PASTE]
```
Cross-project relationships and triggers: [DESCRIBE]

Run this prompt with AI

Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.

Why this prompt works

There are 4-5 ways to compose pipelines (DAG, child, multi-project, API trigger, needs:project:) and they’re not interchangeable. Choosing the right one upfront avoids a tangled “everything triggers everything” setup. This prompt forces a use-case-first design.

How to use it

  1. State the use case in plain language before picking a mechanism. “I want X to happen when Y” is the right level.
  2. Map projects and owners. Cross-project pipelines work best when team boundaries are clear.
  3. Decide blocking vs. fire-and-forget upfront (trigger:strategy: matters).
  4. Plan for variable contract: what does downstream need? Pass explicitly.

Mechanism selector

NeedUse
Monorepo: run only changed subproject’s CIDynamic child pipeline (parent generates child YAML)
Library A’s release should trigger consumer B’s CIMulti-project trigger from A → B
External tool kicks off a pipelineAPI trigger with trigger token
Project B needs artifacts from A’s latest mainneeds:project: (couples projects; consider Package Registry)
Same-project, different stages, parallelizeDAG with needs: (no child pipeline needed)
Test matrix that’s known at YAML-write timeparallel:matrix: (no child)
Test matrix discovered at runtimeDynamic child pipeline

Patterns

Parent → Child (static)

# .gitlab-ci.yml
trigger-subproject-a:
  trigger:
    include: subproject-a/.gitlab-ci.yml
    strategy: depend                   # parent waits for child
  rules:
    - changes:
        - subproject-a/**/*

trigger-subproject-b:
  trigger:
    include: subproject-b/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - subproject-b/**/*

Parent → Child (dynamic, monorepo pattern)

# .gitlab-ci.yml
stages: [generate, trigger]

generate-children:
  stage: generate
  image: alpine:3.20
  script:
    - apk add --no-cache git
    - ./scripts/detect-changes-and-emit-yml.sh > children.yml
  artifacts:
    paths: [children.yml]
    expire_in: 1 hour

trigger-children:
  stage: trigger
  needs: [generate-children]
  trigger:
    include:
      - artifact: children.yml
        job: generate-children
    strategy: depend

Multi-project trigger

# In project "platform/library-a"
deploy-and-notify-consumers:
  stage: deploy
  script: ./deploy.sh
  trigger:
    project: platform/consumer-b
    branch: main
    strategy: depend
  variables:
    UPSTREAM_VERSION: $CI_COMMIT_TAG

needs:project: (artifact pull)

# In consumer project
build:
  needs:
    - project: platform/library-a
      job: build-binary
      ref: main
      artifacts: true
  script:
    - ls -la bin/  # has library-a's binary

(Requires target project to allow the caller in Job token permissions.)

API trigger (external)

curl --request POST \
  --form "token=$TRIGGER_TOKEN" \
  --form "ref=main" \
  --form "variables[VERSION]=1.2.3" \
  "https://gitlab.example.com/api/v4/projects/<id>/trigger/pipeline"

Common findings this catches

  • Child pipeline never startstrigger:include: path doesn’t exist in the parent commit. Test with git show <sha>:subdir/.gitlab-ci.yml.
  • Parent shows green, child failed silently → missing strategy: depend; parent’s trigger: job exits success after launching child.
  • Dynamic-child YAML has syntax error → no error in the parent log; the child pipeline shows as failed at the API level. Lint the generator.
  • Cross-project trigger 404 / Forbidden → Job token permissions in the target project don’t include the source. Allow in Settings → CI/CD.
  • Variables not appearing in childtrigger:variables: only passes the listed ones. Add what you need.
  • Trigger loop (A triggers B triggers A) → cycle protection eventually kicks in, but redesign — usually a misunderstood ownership.

When to escalate

  • Trigger relationships forming a dependency graph nobody understands — diagram it, simplify, prefer Package Registry for library handoffs.
  • Cross-team triggers without clear ownership of failures — establish on-call for downstream pipelines.
  • Trigger tokens leaked to git history — rotate immediately, scrub history, audit pipeline runs since the leak.

Related prompts

More GitLab CI/CD prompts & error guides

Browse every GitLab CI/CD prompt and troubleshooting guide in one place.

Free download · 368-page PDF

Reading prompts? Get all 500 in one free PDF

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.