SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free Learning Roadmaps

GitLab CI/CDProjects

Portfolio-ready projects to demonstrate your skills

📄
Last updated Aug 2026
Expert Content

GitLab CI/CD — Portfolio Projects

Build these 3 projects to prove GitLab CI/CD mastery. Each includes code, architecture, and interview talking points.


Project 1: Multi-Stage Pipeline With Artifacts and Cache

Level: Beginner | Time: 1 day | GitLab: gitlab-ci-multistage-pipeline

What you build: A build → test → deploy pipeline for a small application, correctly using artifacts to pass build output between stages and cache to speed up dependency installation across runs.

`.gitlab-ci.yml`

yaml
stages: [build, test, deploy]

variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

cache:
  paths: [.cache/pip]

build:
  stage: build
  script:
    - pip install -r requirements.txt
    - python -m build
  artifacts:
    paths: [dist/]
    expire_in: 1 hour

test:
  stage: test
  script:
    - pip install -r requirements.txt
    - pytest tests/

deploy:
  stage: deploy
  script:
    - echo "Deploying $(ls dist/)"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Interview points

Cache speeds up repeated runs (same dependencies reused); artifacts pass specific files between stages of the same pipeline run — conflating the two is a common early mistake
rules: gating deploy to main only, replacing the deprecated only:/except: syntax
expire_in on artifacts — a real cost/storage consideration, not just a default to leave alone

Steps

1.Create a small application with a real build step (not just an echo)
2.Write the three-stage pipeline above, verifying the artifact actually carries build output into the test stage
3.Add a cache key scoped to the dependency lockfile so cache invalidates correctly when dependencies change
4.Confirm the deploy stage only runs on main, not on feature branches
5.Document the artifact-vs-cache distinction in the README in your own words

Project 2: DAG Pipeline With Security Scanning

Level: Intermediate | Time: 2 days | GitLab: gitlab-ci-dag-security-scan

What you build: A needs:-based DAG pipeline (jobs depending on specific other jobs, not full stages) with GitLab's built-in SAST and dependency scanning integrated.

DAG structure with `needs:`

yaml
stages: [build, test, scan, deploy]

build-frontend:
  stage: build
  script: [echo "building frontend"]

build-backend:
  stage: build
  script: [echo "building backend"]

test-frontend:
  stage: test
  needs: [build-frontend]   # Doesn't wait on build-backend
  script: [echo "testing frontend"]

test-backend:
  stage: test
  needs: [build-backend]    # Doesn't wait on build-frontend
  script: [echo "testing backend"]

include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml

Interview points

needs: removes the stage-bottleneck problem — test-frontend starts the moment build-frontend finishes, without waiting for build-backend to also complete, which a plain stage-sequential pipeline would force
include: pulling GitLab-provided security templates is the concrete DevSecOps advantage over Jenkins referenced throughout this guide — SAST and dependency scanning in a few lines, not custom tooling
Reading scan results in the Merge Request security widget, not just the pipeline log — this is where the security findings actually surface to a reviewer

Steps

1.Build a repo with genuinely independent frontend/backend build+test paths
2.Write the DAG pipeline with needs: and confirm (via pipeline visualization) that frontend and backend jobs run in parallel rather than stage-sequential
3.Include GitLab's SAST and Dependency Scanning templates
4.Introduce one intentional vulnerability (an outdated dependency) and confirm it surfaces in the Security Dashboard
5.Document the DAG's actual time savings versus a stage-sequential equivalent in the README

Project 3: Multi-Project Pipeline With Runner Fleet Autoscaling

Level: Advanced | Time: 3-4 days | GitLab: gitlab-ci-multiproject-fleet

What you build: A pipeline that triggers a downstream pipeline in a separate project, running on a Kubernetes-executor runner fleet that autoscales.

Multi-project trigger

yaml
trigger-deploy-project:
  stage: deploy
  trigger:
    project: my-group/deploy-project
    branch: main
    strategy: depend   # Parent pipeline waits on and reflects child's status

Kubernetes executor runner (autoscaling)

bash
helm install gitlab-runner gitlab/gitlab-runner \
  --namespace gitlab-runner --create-namespace \
  --set gitlabUrl=https://gitlab.com/ \
  --set runnerRegistrationToken=<TOKEN> \
  --set 'runners.executor=kubernetes' \
  --set 'runners.kubernetes.namespace=gitlab-runner'

Interview points

strategy: depend is the specific config that makes a multi-project pipeline behave as one logical deployment rather than a fire-and-forget trigger — the parent pipeline's success/failure genuinely reflects the child's outcome
Kubernetes executor autoscaling to zero when idle is the concrete production answer to "how do you avoid paying for idle CI capacity"
Multi-project pipelines are the real-world pattern for a CI/CD system split across microservices in separate repos, each with independent pipelines that still need to coordinate a shared deployment

Steps

1.Set up two GitLab projects — an application project and a deploy project
2.Configure the application project's pipeline to trigger the deploy project's pipeline with strategy: depend
3.Set up a Kubernetes-executor runner and confirm job pods scale up and back down to zero
4.Intentionally fail the downstream pipeline and confirm the parent pipeline correctly reflects the failure
5.Document the autoscaling behavior observed (pod count over time) in the README

Portfolio Checklist

[ ] All repos public on GitLab with clear READMEs
[ ] README includes the full .gitlab-ci.yml and how to reproduce the pipeline
[ ] Can explain the artifact-vs-cache distinction and needs:-based DAG pipelines without notes in an interview
[ ] Project 2's security scan findings are screenshotted from the Security Dashboard, not just described
[ ] Project 3 demonstrates real observed autoscaling (pod count before/during/after a pipeline run), not just the runner configuration
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Up Next
💬
GitLab CI/CDInterview Q&A
Most asked interview questions with detailed answers
Also Worth Exploring
← Back to all GitLab CI/CD modules
LabsInterview Q&A