All resources
CI/CD · Interview prep

CI/CD interview questions

CI/CD interview questions from fresher to senior — pipeline fundamentals, practical pipeline design, deployment strategies, and secure CI/CD, each answer tagged by experience level.

ExperienceAll levelsFresherJuniorMidSenior

Fresher 0–1y · Junior 1–3y · Mid 3–6y · Senior 6+y — every answer is tagged so you can prep for your level.

Fundamentals
What is CI and what is CD?Fresher

Continuous Integration means every change is merged and automatically built and tested frequently. Continuous Delivery keeps the build always deployable with a manual release gate; Continuous Deployment removes that gate and ships automatically.

commitbuildtestdeploy

CI stops at a tested artifact; CD (delivery) adds a manual gate, CD (deployment) ships automatically.

What are the typical stages of a pipeline?Fresher

Build (compile/package), test (unit, integration, lint, security scans), publish an artifact, and deploy/promote through environments. Each stage should fail fast and give clear feedback.

A minimal .gitlab-ci.yml
stages: [build, test, deploy]

build:
  stage: build
  script: [make build]

test:
  stage: test
  script: [make test]
What is an artifact and why store it?Junior

The immutable output of the build (jar, container image, binary). You build it once, store it in a registry with a version, and promote that same artifact across environments — never rebuild per environment.

Build once, promote the same bits
docker build -t registry/app:$CI_COMMIT_SHA .
docker push registry/app:$CI_COMMIT_SHA
# deploy that exact tag to dev, then stg, then prod
What is a runner or agent?Junior

The worker that executes pipeline jobs. It can be shared or dedicated, ephemeral or long-lived; ephemeral runners give a clean environment per job and reduce the blast radius of a compromised build.

Ephemeral runners (a fresh container or VM per job) are strongly preferred: no state leaks between jobs and a compromised build cannot persist. Long-lived runners are faster but accumulate secrets, caches, and drift — a bigger blast radius.

What triggers a pipeline?Fresher

Common triggers are a push or merge request, a tag (for releases), a schedule (nightly), a manual or API call, or an upstream pipeline. Scope each job to the right trigger with rules.

Run a job only on main
deploy:
  script: [./deploy.sh]
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
Pipelines in practice
How do you speed up a slow pipeline?Mid

Cache dependencies, run independent jobs in parallel (and test matrices), split long test suites, use incremental/affected builds in monorepos, and keep images small. Measure stage timings before optimizing.

Measure stage timings first, then attack the biggest: cache dependencies, run independent jobs in parallel and split slow test suites, and in a monorepo build only what changed. Warm caches and small images matter more than clever tricks.

measure stage timescache depsparallelize / splitbuild only changed
Cache + parallel
test:
  parallel: 4
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths: [.venv/, node_modules/]
  script: [make test]
How should secrets be handled in CI?Mid

Store them in the platform’s secret store or a vault, inject as masked env vars at run time, never echo them, scope them to the jobs that need them, and prefer short-lived OIDC tokens over static credentials.

Keep secrets in the platform store or a vault, inject as masked variables at run time, scope them to the jobs and branches that need them, and never echo them. Prefer short-lived OIDC tokens so there is nothing static to leak or rotate.

Fetch at runtime, never echo
deploy:
  script:
    - vault kv get -field=token secret/deploy   # fetch at runtime
    # never: echo "$DEPLOY_TOKEN"
  environment: production
Caching vs artifacts — what is the difference?Mid

Cache speeds up future runs by reusing inputs (dependencies) and is best-effort. Artifacts are outputs of a job passed to later stages (a built binary, a report) and are guaranteed present. Do not use cache to hand build output to deploy.

Artifact hands build to deploy
build:
  script: [make build]
  artifacts:
    paths: [dist/]
    expire_in: 1 week
How do you promote a build across environments?Mid

Promote the same versioned artifact with environment-specific config injected at deploy time. Gate production behind approvals and automated checks so dev/staging/prod run identical bits, differing only in configuration.

build oncedeploy devdeploy stagingapprove -> prod
Same artifact, per-env config
# one image tag, config injected at deploy
helm upgrade app ./chart -f values-prod.yaml --set image.tag=$CI_COMMIT_SHA
How do you design pipelines for a monorepo?Senior

Detect changed paths and build/test only affected components (Nx, Bazel, Turborepo, or path filters), share caches, and fan out per-service pipelines — otherwise every commit rebuilds everything and CI becomes the bottleneck.

Detect which paths changed and run only the affected components (rules:changes, or a build graph like Nx/Bazel/Turborepo), share caches, and fan out per-service child pipelines. Otherwise every commit rebuilds the whole repo and CI becomes the bottleneck.

Run a job only when its path changed
api-test:
  script: [make -C services/api test]
  rules:
    - changes: [services/api/**/*]
How do you make a job reusable?Mid

Factor shared config into templates — GitLab extends/include, GitHub reusable workflows or composite actions — so pipelines stay DRY and a fix lands everywhere at once. Hidden keys act as base templates.

extends a base job
.base-test:
  image: python:3.12
  before_script: [pip install -r req.txt]

unit:
  extends: .base-test
  script: [pytest -q]
Deployment strategies
Blue-green vs canary vs rolling?Mid

Blue-green flips all traffic between two identical environments (instant rollback); canary shifts a small percentage first and watches metrics before ramping; rolling replaces instances gradually. Choice trades speed, cost, and risk control.

Blue-green keeps two full environments and flips the router — instant rollback, double the infra. Canary shifts a small slice and watches metrics before ramping — safest, needs good telemetry. Rolling replaces instances in place — cheapest, slower to roll back.

deploy new (green/canary)shift some trafficwatch metricsramp to 100% or roll back
How do you roll back a bad deploy?Mid

Re-deploy the previous known-good artifact (or flip blue-green/canary weight back). Keep deploys immutable and versioned so rollback is a redeploy, and decouple risky DB migrations so they are backward compatible.

Redeploy known-good
kubectl rollout undo deploy/web        # previous ReplicaSet
helm rollback app 42                   # previous release
# blue-green: point the router back to blue
How do feature flags change deployment?Mid

They separate deploy from release — you ship code dark and enable it per cohort at runtime, enabling gradual rollout, instant kill-switch, and testing in production without a redeploy. The cost is flag lifecycle management.

Flags decouple deploy from release: ship code dark, then enable per cohort at runtime — gradual rollout, an instant kill switch, and testing in prod without a redeploy. The cost is lifecycle: stale flags become tech debt and must be retired.

How do you gate production deploys?Mid

Use protected environments with required approvals, required status checks, and a manual promotion step. The pipeline can reach prod only after review and green checks, and only from the main branch.

Manual gate to prod
deploy-prod:
  stage: deploy
  when: manual                 # requires a human click
  environment: production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
How do you handle database migrations in a pipeline?Senior

Make them backward compatible and run them as a separate, ordered step (expand/contract): add columns before code uses them, deploy code, then remove old columns in a later release — never a destructive migration coupled to a rolling deploy.

Use expand/contract so schema and code are always compatible: deploy an additive migration (new nullable column), then the code that uses it, backfill, and only a later release drops the old column. A destructive migration coupled to a rolling deploy breaks the old pods still running.

expand (additive)deploy codebackfillcontract (drop old) later
Secure CI/CD
What is pipeline injection and how do you prevent it?Senior

Untrusted input (PR titles, branch names, fork code) executed by the pipeline can run attacker commands. Mitigate by not running privileged jobs on untrusted PRs, quoting/validating inputs, and isolating fork builds without secrets.

Untrusted input (PR title, branch name, fork code) interpolated into a shell runs with your pipeline privileges. Never run privileged jobs on untrusted PRs, pass input via env vars instead of inlining it into the script, and quote and validate everything.

Bind untrusted input to an env var
# UNSAFE: an expression with attacker-controlled text
#   inlined straight into a run: shell can execute commands
# SAFE: bind it to an env var, then use "$TITLE" quoted
- run: echo "title is $TITLE"
  env:
    TITLE: the-untrusted-value
Why use OIDC instead of stored cloud keys?Senior

The pipeline exchanges a short-lived, workload-bound identity token for temporary cloud credentials, so there are no long-lived secrets to leak or rotate and access is scoped per repo/branch. It is the modern default for CI-to-cloud auth.

The pipeline presents a short-lived, workload-bound identity token to the cloud, which its trust policy exchanges for temporary credentials scoped to that repo/branch. Nothing static is stored, nothing to rotate, and access can be pinned to one workflow.

pipeline OIDC tokencloud trust policySTS temp credsscoped, short-lived
How do you secure third-party actions/plugins?Senior

Pin them to a full commit SHA (not a mutable tag), review and minimize them, restrict which are allowed, and treat them as code with the same trust as your own — a compromised action runs with your pipeline’s privileges.

Pin to an immutable SHA
# tag is mutable and can be moved under you
uses: actions/checkout@v4
# pin to an immutable commit instead
uses: actions/checkout@8f4b7f8a1c...
What is SLSA / build provenance?Senior

A framework of levels for supply-chain integrity; provenance is signed, tamper-evident metadata about how and from what an artifact was built. Higher SLSA levels require hardened, non-falsifiable build systems so consumers can verify origin.

Provenance is signed, tamper-evident metadata recording how, from what source, and by which builder an artifact was produced. SLSA is a tiered framework; higher tiers require a hardened, non-falsifiable builder so a consumer can cryptographically verify origin before deploy.

buildgenerate provenancesign (cosign)verify before deploy
What is a poisoned pipeline execution (pwn request)?Senior

A fork PR that triggers privileged CI — with secrets or a write token — can exfiltrate them or push malicious code (the pull_request_target class of bug). Fix it by never exposing secrets to fork builds, requiring approval to run CI on forks, and separating untrusted build from trusted deploy.

What belongs in a secure pipeline beyond tests?Mid

SAST, dependency/SCA scanning, secret scanning, container and IaC scanning, SBOM generation, and artifact signing — with a sane failure policy so criticals block and noise does not, plus least-privilege runners.

Security stages that gate merge
security:
  stage: test
  script:
    - gitleaks detect              # secret scanning
    - trivy fs --exit-code 1 .     # deps + image CVEs
    - checkov -d .                 # IaC misconfig
    - syft . -o cyclonedx > sbom.json
Go deeper
Full, hands-on DevSecOps courses
Browse courses