CI/CD Platform Overview
The Big Four Platforms
Most teams in 2025 use one of four CI/CD platforms. Each has its own configuration format and hosting model, but they all share the same core concepts: triggers, jobs, steps, environment variables, secrets, and artifacts.
| Platform | Config Format | Hosted/Self-Hosted | Strengths | Limitations |
|---|---|---|---|---|
| GitHub Actions | YAML (.github/workflows/) |
Hosted (+ self-hosted runners) | Native GitHub integration, marketplace of actions, generous free tier | Debugging workflows can be slow (push-and-pray) |
| GitLab CI | YAML (.gitlab-ci.yml) |
Both | Built-in container registry, review apps, strong DevSecOps features | YAML complexity grows quickly |
| Jenkins | Groovy (Jenkinsfile) |
Self-hosted | Maximum flexibility, massive plugin ecosystem | Maintenance burden, UI feels dated |
| CircleCI | YAML (.circleci/config.yml) |
Hosted | Fast execution, excellent caching, orbs for reuse | Cost scales with parallelism |
Shared Concepts Across All Platforms
Regardless of which platform you use, the following concepts work the same way. Understanding these makes switching platforms straightforward.
Triggers
Triggers define when a pipeline runs. Common triggers include:
- Push to branch: Run on every code push (most common for CI)
- Pull request / merge request: Run when a PR is opened or updated
- Schedule (cron): Run on a timer for nightly regressions or data freshness checks
- Manual dispatch: Allow humans to trigger pipelines with parameters (useful for deploying to specific environments)
- Tag creation: Run when a new release tag is pushed
Jobs and Steps
A job is a unit of work that runs on a single machine (runner). Jobs can run in parallel or sequentially depending on dependencies. A step is a single command or action within a job.
Pipeline
└── Job A (runs first)
├── Step 1: Checkout code
├── Step 2: Install dependencies
└── Step 3: Run unit tests
└── Job B (depends on Job A)
├── Step 1: Checkout code
├── Step 2: Run integration tests
└── Step 3: Upload test reports
Environment Variables and Secrets
Environment variables configure behavior without hardcoding values. Secrets are encrypted environment variables for sensitive data like API keys, passwords, and tokens.
Rules for secrets:
- Never commit secrets to version control
- Use the platform's secret store (GitHub Secrets, GitLab CI Variables, Jenkins Credentials)
- Rotate secrets regularly
- Scope secrets to the minimum required access (repository-level, not organization-level, when possible)
Runners
A runner is the machine where your pipeline executes. Hosted runners are provided by the platform (convenient but with limited customization). Self-hosted runners are machines you manage (more control, better for specialized hardware or internal network access).
When to use self-hosted runners:
- Tests need access to internal services behind a firewall
- You need specialized hardware (GPU, mobile devices)
- Pipeline volume makes hosted runners expensive
- Compliance requirements mandate that code never leaves your network
Choosing a Platform
For most teams, the choice is simple: use what integrates with your source control. If your code is on GitHub, use GitHub Actions. If it is on GitLab, use GitLab CI. The friction of using a separate CI platform (e.g., Jenkins with GitHub) rarely justifies the benefits.
Choose Jenkins when:
- You need complex, highly customized pipelines with plugins for niche tools
- You have a dedicated DevOps team to maintain the Jenkins infrastructure
- Your organization already has a mature Jenkins setup
Choose CircleCI when:
- You need the absolute fastest execution times
- Your team uses multiple source control platforms
- You want orbs (reusable pipeline packages) to reduce boilerplate
Platform-Specific Tips for QA
GitHub Actions
- Use the
actions/upload-artifactandactions/download-artifactactions to pass test results between jobs - The
serviceskeyword spins up Docker containers (databases, message queues) as sidecars for integration tests - Use
workflow_dispatchinputs to let QA trigger test runs against specific branches or environments manually
GitLab CI
rulesandonly/exceptcontrol when jobs run -- use them to skip expensive tests when only docs changeartifacts:reports:junitparses JUnit XML and shows test results inline in merge requests- Review apps can deploy each merge request to a temporary environment for manual testing
Jenkins
- Use
Jenkinsfile(declarative or scripted pipeline) over freestyle jobs for reproducibility - The Blue Ocean plugin provides a modern UI for pipeline visualization
- Shared libraries let you reuse pipeline logic across multiple projects
CircleCI
- Orbs are pre-packaged pipeline steps. The
cypress/orbandplaywright/orbcan save hours of setup - Workspaces persist data between jobs in a workflow (similar to GitHub Actions artifacts but more lightweight)
- Test splitting with
circleci tests splitdistributes tests across parallel containers automatically
Hands-On Exercise
- Pick the platform your team uses (or GitHub Actions if you are learning independently)
- Create a pipeline that:
- Triggers on push and pull request
- Has two jobs:
lintandtest - The
testjob depends onlintpassing - Uses caching for dependencies
- Uploads test results as artifacts
- Intentionally break a test and verify the pipeline fails and produces useful artifacts
- Add a scheduled trigger for a nightly run
This exercise covers the fundamentals that apply to every platform. Once you have built one pipeline from scratch, the concepts transfer everywhere.