Platform comparisons usually become feature lists, and feature lists do not decide anything — every platform can build a container. The question that decides it is what your team can operate on a bad week, and what your constraints actually are.
Topic 1: The Comparison That Matters
| Jenkins | Cloud Build | GitHub Actions | GitLab CI | |
|---|---|---|---|---|
| You run the server | Yes | No | No (or self-hosted runners) | Either |
| Config | Jenkinsfile | cloudbuild.yaml | .github/workflows/*.yml | .gitlab-ci.yml |
| Extensibility | ~1,900 plugins | any container | marketplace actions | any container |
| Cloud identity | stored creds, or OIDC | native service account | OIDC | OIDC |
| Orchestration | strongest — matrix, parallel, input, libraries | weakest — a DAG of steps | good | good, with DAG and parent-child |
| Secrets | own store, or external | Secret Manager | repo/org secrets, or OIDC | CI variables, or Vault |
| Cost model | your infrastructure + your time | per build-minute | per minute, free tier for public | per minute, or self-hosted |
| Locks you into | nothing (and everything you built) | GCP | GitHub | GitLab |
What each is genuinely best at:
- Jenkins — complex orchestration, heterogeneous builds, on-premises or air-gapped, and anything where you need to do something nobody anticipated. It will do it, and you will operate it.
- Cloud Build — GCP-native builds where you want no controller and native identity. Weak at multi-environment promotion, which is why it pairs with Cloud Deploy.
- GitHub Actions — repositories already on GitHub. The integration is the feature; the marketplace is both the strength and the supply-chain risk.
- GitLab CI — one integrated tool for repo, CI, registry and deployment, self-hostable when that matters.
Topic 2: The Constraints That Actually Decide
Work through these before comparing features. Any one of them can settle the question on its own:
Where does the code live? If it is on GitHub, Actions removes an entire integration surface. Fighting that costs more than it returns.
Where does it deploy? A GCP-only estate makes Cloud Build plus Cloud Deploy the low-friction path. A multi-cloud estate argues for something neutral.
Can it be a hosted service? Air-gapped, regulated, or on-premises environments frequently answer no, and that leaves Jenkins or self-hosted GitLab.
Who operates it? A team of four with no platform engineer should not run Jenkins. The controller, the plugins, the agents and the backups are a part-time job that nobody has been given.
What does the pipeline need to do? A matrix across six platforms with dynamic parallelism and human approvals is Jenkins’ home ground. Build-test-push is everyone’s.
What already exists? Two hundred working Jenkins pipelines are an asset. “Migrate everything to X” is usually a worse plan than “new services start on X, and Jenkins keeps what works”.
Topic 3: Push or Pull
Independent of the CI tool, deployment happens one of two ways — and this choice matters more than the platform choice.
Push — the pipeline holds cluster credentials and applies the change. Simple, imperative, and drift is invisible between deploys.
Pull (GitOps) — a controller in the cluster watches Git and reconciles. CI’s job ends at “commit the new tag”; Argo CD or Flux does the rest.
Push Pull
CI has cluster credentials cluster pulls; CI has none
"it deployed" = the command exited "it deployed" = the controller reports synced
drift invisible until next deploy drift detected and corrected
rollback = run an older deploy rollback = revert the commit
one system to reason about two, and the handoff is a commit
The practical rule: one cluster and a small team can stay with push. More than one cluster, or a desire not to give CI cluster credentials, means pull. Many mature estates run both — GitOps for the platform baseline, and a push-based release tool (Cloud Deploy, or a Jenkins deploy stage) for application promotion where the audit trail and approvals matter.
What you must not do is run both against the same resource. Two owners means they alternate, and the resulting flapping is genuinely hard to diagnose. Pick one owner per release and make it obvious in the repository which one it is.
Topic 4: Migrating Without a Rewrite
The strategy that works, and the one that consistently fails.
Fails: a six-month project to move 200 pipelines, during which both platforms are maintained, nobody trusts either, and the new one accumulates the same workarounds as the old.
Works:
1. Freeze. New services go on the new platform. No exceptions.
2. Move the noisiest pipeline first — the one people complain about.
It proves the platform and it buys goodwill.
3. Move the simple, high-volume ones next. Fast wins, real load.
4. Leave the genuinely weird ones on Jenkins, possibly forever.
A Jenkins that runs six exotic pipelines is a small thing to operate.
5. Delete the pipelines nobody runs. This is typically a third of them.
The portability that reduces the cost of any migration is worth building for regardless of your platform:
□ every step is a script in the repository, not a platform-specific step
□ every step runs in a pinned container
□ every step can be run locally with one command
□ the platform config is a thin wrapper: checkout, then run ./ci/build.sh
□ nothing important is configured in a web UI
A pipeline written this way is a Jenkinsfile or a cloudbuild.yaml of twenty lines around scripts that work anywhere. That is also, independently, the easiest pipeline to debug.
Topic 5: The Costs Nobody Puts in the Spreadsheet
Jenkins: the controller, the plugin upgrades, the security advisories, the backup drills, the agent fleet, and the person who knows how it works. Real, recurring, and usually uncounted.
Hosted platforms: per-minute billing that grows with your test suite; egress charges when builds pull large images; and the marketplace supply-chain risk — a third-party action or builder image running with your credentials. Pin those by digest, exactly as you pin your own images.
Both: the cost of a slow pipeline. Ten engineers waiting an extra eight minutes per merge, ten merges a day, is over an hour of engineering time daily — which dwarfs the infrastructure line item and never appears next to it.
And the cost of a pipeline nobody trusts, which is the largest of all: batched changes, larger releases, more risk per deploy, and slower recovery. That is the number the DORA metrics from the first lesson actually measure.
Topic 6: A Defensible Recommendation
The form of the answer, whatever your conclusion:
Our constraint is: [where code lives / where it deploys / who operates it]
Therefore we choose: [platform]
We accept: [the specific lock-in or operational burden]
We keep Jenkins for: [the exotic pipelines, or nothing]
Delivery model: [push or pull, and who owns each release]
We will revisit if: [the condition that would change the answer]
That last line is what makes it a decision rather than an allegiance. “We will revisit if we adopt a second cloud” or “if the estate exceeds twenty services” is a concrete trigger, and it stops the choice from being re-argued every quarter.
Try it yourself: implement the same build on two platforms and compare the line counts and the durations. The result is often that the pipelines are nearly identical and the difference is entirely in what you operate — which is exactly the finding that makes the decision easy.
Common mistake: choosing a platform on its feature list and discovering the constraint afterwards. The team that picks Jenkins for its plugin ecosystem and then has no one to patch it, or picks a hosted platform and then needs to build inside an air-gapped network, has made a decision that the constraint would have made for them in five minutes.