Abhinav C

Jenkins isn't your problem. Your Jenkinsfile is.

Every few years a team decides Jenkins is the reason their builds are slow and flaky, and moves to GitLab CI, GitHub Actions or CodePipeline. Six months later the new pipelines are slow and flaky too, because they were copied line for line.

Jenkins has real costs: plugin upgrades, a controller to patch, Groovy’s oddities. But most pipeline pain comes from three design choices that work just as badly on any CI system.

Mistake 1: logic in the pipeline file

A 600-line Jenkinsfile full of shell, string manipulation and if statements on branch names can only be tested by pushing a commit and waiting. Nobody can run it locally, and every change is a gamble.

Keep the pipeline file to orchestration: stage names, ordering, parallelism, credentials, where artifacts go. Put the work in scripts or a Makefile that run the same way on a laptop:

stage('Test') {
  steps { sh 'make test' }
}

If make test passes locally, it passes in CI. Changing CI tools later becomes a weekend, not a quarter.

Mistake 2: long-lived, hand-tended agents

An agent that has run builds for two years has a disk full of caches, tools installed by hand, and state left behind by other jobs. Builds pass on agent 3 and fail on agent 5, and nobody knows why.

Use ephemeral agents: a fresh container or VM per build, from an image built in code. Jenkins does this with its Kubernetes or EC2 plugins, and hosted runners do it by default. Caches belong in an explicit cache (an artifact store, a registry, a mounted volume with a key), not in whatever happened to be on disk.

Mistake 3: a controller nobody can rebuild

If your Jenkins controller died tonight, could you rebuild it? For many teams the honest answer is “from a backup, probably.” Its configuration lives in hundreds of screens that people clicked through over the years.

The Configuration as Code plugin (JCasC) defines the controller in YAML: security, credentials references, agents and tool installations. Pair it with a pinned plugin list and a container image, and the controller becomes something you can replace rather than something you have to protect.

Why this matters more now

Coding agents open pull requests now, and they don’t get tired of waiting for CI. Teams adopting them should expect more pipeline runs per day, from contributors who can’t ask a colleague why a build is flaky. The pipeline has become the main reviewer that never gets bored: it has to be fast, deterministic and trusted, because more of the code it checks was written by something that will believe whatever it reports. A flaky pipeline used to waste a person’s afternoon. Now it teaches an agent the wrong lesson at scale.

A test for any CI system

Ask these four questions of your pipelines, whatever runs them:

Question Healthy answer
Can a developer run the build locally? Yes, with one command
Does a build depend on which agent ran it? No, agents are disposable
Can the CI server be rebuilt from Git? Yes, including plugins and config
Is shared pipeline logic versioned and reviewed? Yes, in a shared library or template

If all four answers are healthy, the choice of CI tool is mostly about cost and convenience. If they aren’t, moving tools takes all four problems with you, plus a migration.

Filed under: migrations that move the mess.

More writing