Most articles about leaving Jenkins are written for someone who does not have Jenkins. They compare pipeline syntax, note that modern platforms have nicer YAML, and conclude that you should switch. That advice is useless to the team it is aimed at, because that team does not have a blank repository. It has several hundred jobs, a shared Groovy library nobody fully understands, a controller with an uptime measured in years, and at least three jobs that are load-bearing for a process outside engineering.
The real question is not which platform is better. On syntax and developer experience, most of them are. The question is how you move an estate of that size without a code freeze, without breaking the release process, and without discovering in month four that eleven jobs depended on a plugin with no equivalent anywhere.
There are three things that determine whether this goes well. Whether you audited the estate before choosing a target, because the plugin inventory eliminates targets. Whether you picked a migration strategy that tolerates running both systems for a long time, because you will. And whether you had an honest answer for the Groovy shared library, because that is where the institutional knowledge lives and it does not port.
Key takeaways
- Audit before choosing. The plugin inventory and the job taxonomy determine which targets are viable, and a target chosen before the audit is usually the wrong one.
- Expect to run both systems for a long time. Any strategy that requires a cutover date is a strategy that will slip and then get abandoned halfway.
- Most jobs are variations on a handful of templates. Migrate by class rather than one at a time, and the long tail shrinks faster than the job count suggests.
- The Groovy shared library is the hard part. Some of it is genuinely business logic and should become a versioned tool your pipelines call, not pipeline code at all.
Audit the estate before you choose a target
You cannot evaluate a replacement against a system you have not characterised. Four inventories, and each one eliminates options.
Job taxonomy. Group every job by what it actually does: build and test a service, publish a library, build a container image, deploy to an environment, run a scheduled maintenance task, run a report for somebody outside engineering. In most estates a large majority of jobs fall into a handful of shapes, and the practical work is migrating those shapes rather than the jobs. The long tail is where the surprises live, and the scheduled and report jobs are where the non-engineering dependencies hide.
Plugin inventory. List every installed plugin and, more importantly, which jobs actually use each one. Most estates have a large number installed and a much smaller number in real use. This list is your compatibility filter: if something depends on a plugin covering a legacy toolchain, a hardware interface, or an internal system, and no target platform has an equivalent, that job is either staying, being rewritten as a script, or blocking the migration.
Credential and agent inventory. Which credentials exist, which jobs use them, and what they can reach. Jenkins estates accumulate credentials with far more privilege than any single job needs, and migration is the only realistic opportunity you will get to fix that. Similarly, list the agents: their labels, what is installed on them, and which jobs require them. Agents with manually installed toolchains are a hidden dependency that breaks quietly when you move.
Trigger inventory. What starts each job. Source control events are easy. Timers, upstream job completion, manual runs by named humans and inbound webhooks from other systems are all things that need an equivalent on the other side, and the last category is the one that gets missed because nobody in engineering owns the caller.
Needs first-hand data: Produce the four inventories for your own estate and publish the distribution: jobs per taxonomy class, plugins installed versus plugins actually referenced by a job, credentials per job, and triggers by type. The ratio of installed to used plugins, and the size of the long tail after classification, are the two numbers that predict how long the migration takes, and neither is guessable from the outside.
Migration strategies that survive contact
Strangler, by job class. Pick the largest taxonomy class, usually build-and-test for services, and build a template for it on the target platform. Migrate one team, then the rest of that class. Move to the next class. This works because it front-loads the reusable work and because progress is visible early, which matters for keeping the project funded.
Both systems, indefinitely. Accept from the start that Jenkins will still be running a year in, handling the long tail. That is not failure, it is the correct plan. What makes it work is deciding early that no new jobs are created on Jenkins, which converts the estate from growing to shrinking without anyone having to do anything heroic.
New work on the new platform, immediately. The cheapest migration is the jobs you never create. Enforce this from day one, before the rest of the plan exists, because every month of delay adds to the thing you are trying to shrink.
Parallel-run the critical jobs. For anything that matters, run both pipelines on the same commit and compare the artifacts. This is the only honest validation, and it catches the class of problem where the new pipeline succeeds but produces something subtly different: a different base image, a missing build flag, a different dependency resolution.
Avoid the big-bang freeze. A freeze long enough to migrate hundreds of jobs is long enough to be cancelled. It also concentrates all the risk into one weekend, which is exactly the wrong shape for a change to the system that builds everything.
Decide what not to migrate. Some jobs should simply be deleted, and the audit is when you find out which. Jobs that have not run in a year, jobs whose output nobody consumes, and jobs duplicating another job are all common. Deleting them is the highest-return work in the entire project.
Plugin equivalence: what maps and what does not
The plugin inventory sorts into four buckets, and knowing which bucket each falls into tells you how much work is left.
Built in on the target. Source checkout, credential storage, artifact archiving, test result parsing, container builds, basic notifications. Every modern platform handles these natively, so these plugins simply disappear. This is usually most of the list by usage count.
Available as a reusable step. Cloud CLI integration, static analysis, container scanning, publishing to package registries. These exist as marketplace actions, orbs or pipeline templates, and the work is configuration rather than engineering. Note that this is also where you inherit a new supply chain problem, so apply allowlisting and digest pinning as part of the migration rather than afterwards.
Replaceable with a script. A surprising share of plugin usage is a thin wrapper around a command line tool. Once your pipeline step is just a container image with that tool installed, the plugin has no reason to exist. This bucket usually shrinks the perceived problem substantially, and scripts are more portable than plugins were.
No equivalent. Plugins for legacy build systems, hardware-in-the-loop testing, mainframe integration, proprietary internal systems, or niche reporting formats. This bucket decides the project. Options, in order of preference: rewrite the integration as a container image that any platform can run, keep those specific jobs on Jenkins indefinitely, or retire the capability. Pretending the bucket is empty is how migrations stall at eighty percent.
One structural warning. Plugin behaviour is frequently configured in the Jenkins UI rather than in code, which means the configuration is not in your repository and is not in your audit unless somebody goes looking. Global tool configuration, credential bindings and agent-level environment setup are all commonly invisible this way, and they are exactly what causes a migrated job to fail in a way that makes no sense from reading the pipeline file.
What to do with Groovy pipelines
The shared library is where this gets emotional. It is real code, it encodes years of institutional decisions, it has no tests, and it is written in a language nobody on the team chose.
Start by separating three things that are tangled together inside it.
Orchestration logic is stage ordering, parallelism, conditionals on branch name, retry behaviour. This translates to the target platform’s pipeline syntax directly and is the easiest part. Most of it becomes declarative configuration and gets shorter.
Environment and tooling setup is installing dependencies, configuring toolchains, setting paths. This should not be translated at all. It should become a container image containing the toolchain, which is both faster at build time and portable across platforms. This is the single highest-value refactor in the whole migration and it can be done before you choose a target.
Business logic is version number calculation, environment promotion rules, release note generation, artifact naming conventions, approval routing. This is real software that happens to live in pipeline code. It should become a small versioned tool in a language your team actually uses, invoked by the pipeline as a command. Then it can be tested, it is readable, and it survives the next platform change too.
That last point is the useful reframing. The reason the Groovy library is painful is not Groovy. It is that business logic ended up in a place with no tests, no types anyone reads, and no local execution. Moving it into a proper tool fixes the actual problem, and the migration is just the occasion.
Two practical notes. Scripted pipelines, the ones that are arbitrary Groovy rather than the declarative form, are the hardest to port because they can do anything, and they often do. Budget disproportionately for those. And resist the temptation to build an equivalent shared library on the new platform on day one. Reusable workflows and pipeline includes are good, and rebuilding the same abstraction before you understand the new platform’s idioms reproduces the problem you are escaping.
GitHub Actions

The most common destination, usually because the source repositories are already there and the migration therefore removes a whole integration rather than adding one. Jobs become workflow files beside the code, which also fixes the Jenkins problem where pipeline configuration lived outside the repository it built.
Pros
- Removes the source-to-CI integration entirely when repositories already live there, including credentials and webhooks
- Workflow definitions live with the code, so pipeline changes are reviewed like any other change
- Large marketplace covers most of the second plugin bucket with configuration rather than engineering
- Self-hosted runners give a direct home for jobs that need specific hardware or network access from the old agent fleet
Cons
- Marketplace actions reintroduce the unreviewed-third-party-code problem that plugins created, in a new form
- No equivalent to Jenkins plugins for genuinely legacy toolchains, so the fourth bucket has to be scripted or left behind
- Debugging is weaker than a Jenkins agent you can log into, which is a real loss during migration when you need to compare behaviour
Best for: Estates whose repositories are already on GitHub, where most jobs are build-and-test and the legacy bucket is small.
Pricing: Metered per build minute with machine size and operating system multipliers, or unmetered compute if you attach your own runners.
GitLab CI/CD

The closest philosophical replacement for a self-managed Jenkins, because it can also be self-managed, runs in disconnected environments, and covers registry and environments in the same system. For organisations whose reason for using Jenkins was that it ran on their own hardware, this is often the shortest conceptual distance.
Pros
- Self-managed deployment preserves the property that made Jenkins acceptable to security in the first place
- Includes and extends give a genuine replacement for shared library reuse without resorting to code
- Bundled registry and environments replace several plugin categories at once
- Existing self-hosted agents map cleanly onto runners with tagged capabilities, mirroring Jenkins labels
Cons
- Migrating to a self-managed GitLab install swaps one large operational responsibility for another, which needs to be a deliberate choice
- If your repositories are hosted elsewhere, this becomes a source control migration as well, which doubles the project
- Feature tiering puts some compliance and management capabilities behind paid editions
Best for: Organisations that chose Jenkins for self-management and want to keep that property while modernising the pipeline model.
Pricing: Free self-managed edition with per-seat paid tiers, or hosted subscription with metered compute minutes.
Buildkite

Structurally the most familiar target for a Jenkins team, because the split is the same: a control plane you do not operate and agents you do. Your existing agent machines, with their manually installed toolchains and their network placement, can often be repurposed almost directly, which removes the single most disruptive part of many migrations.
Pros
- Agent model maps almost directly onto Jenkins agents, including labels, tags and specialised machines
- Existing build machines and their network access can be reused, which preserves connectivity to internal systems
- Dynamic pipeline generation is a natural home for logic that currently lives in scripted Groovy
- Removes controller operation, upgrades and plugin management while keeping compute under your control
Cons
- Hosted control plane means build metadata leaves your network, which is a new conversation if the original Jenkins choice was driven by isolation
- You still own agent images, scaling and patching, so the operational burden reduces rather than disappears
- Fewer prebuilt integrations than the marketplace platforms, so more of the second plugin bucket becomes scripting
Best for: Teams whose Jenkins pain is controller and plugin maintenance rather than the agent fleet, and who want to keep builds on their own machines.
Pricing: Per-seat subscription for the control plane, with compute costs appearing on your own infrastructure bill.
CircleCI

A reasonable target when the reason for leaving Jenkins is that builds are slow rather than that maintenance is painful. Its explicit caching, per-job resource classes and timing-based test splitting address the performance problems that Jenkins estates typically accumulate through years of jobs nobody profiled.
Pros
- Explicit cache and workspace primitives make it straightforward to fix the slow builds you are migrating away from
- Timing-based test splitting replaces manually sharded Jenkins jobs, which is a common source of estate sprawl
- Source-host neutral, so it does not force a repository migration alongside the CI migration
- Orbs provide reuse with clearer provenance than an open marketplace
Cons
- Hosted-only compute means jobs requiring specific hardware or internal network access need another answer
- Credit-based metering is a harder cost model to forecast when you are migrating an estate of unknown total volume
- Adds a vendor relationship where Jenkins had none, which is a procurement step some organisations find slow
Best for: Estates where build performance is the driving complaint and the jobs are mostly standard build-and-test work with no exotic hardware requirements.
Pricing: Credit-based metering combining machine size and duration, with tiers adding concurrency and support.
Tekton
The Kubernetes-native answer, and the right one only if you already run Kubernetes and have a platform team. It replaces Jenkins with a set of custom resources rather than a product, which means you get complete control over the execution model and you build the developer-facing layer yourself.
Pros
- Execution in pods gives per-step isolation and reuses your existing cluster autoscaling
- Task and pipeline resources are composable building blocks, which suits standardising a large estate on a few templates
- No controller to operate separately, since the control plane is the cluster you already run
- Vendor-neutral governance removes the licensing and stewardship risk that pushed some teams off Jenkins
Cons
- It is a toolkit, not a product, so the interface your developers use is a project you own
- Requires genuine Kubernetes expertise, which relocates the operational burden rather than reducing it
- Debugging means reading pod logs and resource status, which is a downgrade for application teams used to a Jenkins console
Best for: Platform teams already running Kubernetes who are building an internal developer platform and want CI to be a component of it.
Pricing: Open source with no licence cost. Expense is cluster capacity plus the platform engineering work.
Harness

Worth considering when the Jenkins estate is dominated by deployment jobs rather than build jobs. Its emphasis is on release governance, policy as code across pipelines, and automated verification of deployments against monitoring signals, which addresses a different failure mode than a faster build does.
Pros
- Policy as code lets a platform team enforce standards across a large migrated estate centrally
- Deployment verification and automated rollback replace the bespoke Groovy that many Jenkins deploy jobs contain
- Approval workflows are designed for regulated release processes rather than assembled from plugins
- Clear separation between pipeline authorship and policy, which maps onto separation of duties requirements
Cons
- Introduces a commercial vendor where Jenkins had no licence cost, which is a significant internal justification
- Large feature surface requires a platform team to configure, so it is not a lighter system than what you left
- Oriented toward larger deployments, which makes a single-team pilot feel disproportionate
Best for: Organisations whose Jenkins estate is mostly deployment orchestration and whose real requirement is centralised release governance.
Pricing: Modular subscription by capability, metered on deployments and services rather than build minutes.
CloudBees

The option that is not a migration. Managed controllers, a curated plugin distribution and centralised security and governance on top of the Jenkins you already run. For an estate of several hundred jobs, this addresses the operational pain without touching a single pipeline, which is sometimes the correct answer for this budget year.
Pros
- Preserves every existing job, plugin and shared library, so the migration risk is zero
- Managed controllers solve the sprawl and single-point-of-failure problems that cause most Jenkins outages
- Curated and tested plugin distribution directly targets the version-compatibility failures in the estate
- Commercial support with escalation, which is frequently the specific gap procurement is asking about
Cons
- You remain on the Jenkins architecture, so Groovy pipelines and the plugin model stay exactly as they are
- Paying a licence for a system you previously ran free needs a concrete governance justification internally
- It relieves the symptom rather than reducing the estate, so the underlying modernisation is still ahead of you
Best for: Large estates where the immediate problem is reliability and support rather than pipeline design, and where a migration cannot be funded this year.
Pricing: Commercial subscription over the open source foundation, typically metered by controllers or managed capacity.
How to choose
Let the plugin inventory eliminate first. If a meaningful number of jobs depend on plugins with no equivalent, your choice is between platforms that can run arbitrary containers on machines you control, and the exotic jobs stay on Jenkins regardless.
Ask why you chose Jenkins originally. If it was self-management and network isolation, targets that require a hosted control plane will fail the same review that led you here. If it was flexibility, the container-native platforms all provide that now.
Match the target to the dominant job class. An estate that is mostly build-and-test wants a CI platform. An estate that is mostly deployment orchestration wants a delivery platform. Migrating deployment jobs into a CI tool reproduces the thing you are leaving.
Consider not migrating. If the pain is reliability and support rather than pipeline design, governing the existing estate is cheaper, faster and lower risk than moving it, and it leaves the option open.
| Target | Compute location | Handles legacy toolchains | Migration disruption | Fits when |
|---|---|---|---|---|
| GitHub Actions | Hosted or your runners | Via self-hosted runners and scripts | Low if repos already there | Repositories are on GitHub already |
| GitLab CI/CD | Hosted or self-managed | Yes, self-managed with your runners | High if repos move too | Self-management was the reason for Jenkins |
| Buildkite | Yours only | Yes, reuse existing agents | Low for the agent fleet | Controller maintenance is the pain, not agents |
| CircleCI | Hosted only | Limited, no private network access | Medium | Build performance is the driving complaint |
| Tekton | Your Kubernetes cluster | Via container images | High, you build the platform | You already run Kubernetes with a platform team |
| Harness | Hosted | Via delegates on your network | Medium | The estate is mostly deployment orchestration |
| CloudBees | Your infrastructure | Yes, unchanged | None | Reliability and support are the immediate problem |
Needs first-hand data: For the first migrated job class, record the time spent per job on translation, on debugging behavioural differences found by parallel-running, and on fixing agent or environment assumptions that were invisible in the Jenkins configuration. Divide by job count. That per-job cost, multiplied by the tail after templating, is your actual project estimate, and the third category is invariably the largest and the most underestimated.
Frequently asked questions
How long does migrating a few hundred Jenkins jobs take?
Longer than the estimate, and the variable is not job count. It is the size of the long tail after you classify jobs into templates, plus the number of plugin dependencies with no equivalent. A well-templated estate of several hundred jobs can move quickly for most of the count and then spend as long again on the last part. Plan the schedule around the tail, not the majority.
Do we have to move everything?
No, and planning to is usually the mistake. Keeping a small Jenkins instance for the jobs that genuinely need it is a legitimate end state, provided new jobs are not created there and the remaining set is documented and shrinking. A stable, small, well-understood Jenkins is a very different thing from the estate you have now.
What happens to our Groovy shared library?
Split it. Orchestration becomes pipeline configuration on the new platform. Environment setup becomes a container image. Business logic becomes a small versioned tool your pipelines invoke, written in a language your team maintains. The third part is the one that pays off permanently, because it survives the next migration as well.
Should we just modernise Jenkins instead?
It is a real option and frequently the right one for a year or two. Moving jobs into versioned pipeline definitions in each repository, replacing plugin usage with container-based steps, and consolidating controllers all reduce pain without a platform change. They also happen to be exactly the work that makes a future migration cheap, so the effort is not wasted either way.
How do we handle secrets during the migration?
Do not copy them. Migration is the one opportunity to replace long-lived credentials with federated short-lived ones, scoped per repository, and to remove the over-privileged credentials the estate accumulated. Doing this during the move costs little extra; doing it afterwards is a second project nobody funds. See secrets management for CI/CD and API authentication tools for the identity side.
Related reading
- Best CI/CD platforms — the category map, if you want the wider view before committing to a target.
- Best self-hosted CI/CD tools — the options if keeping builds on your own infrastructure is non-negotiable.
- Best CI/CD platforms for enterprise — the procurement gates any target has to clear.
- GitHub Actions vs GitLab CI vs CircleCI — the three most common destinations compared on the same pipeline.
- Best deployment orchestration tools — where the deployment half of a Jenkins estate usually belongs.