A long-lived Jenkins controller has grown to roughly 200 installed plugins. How do you decide what to remove, and what does removing one actually cost?
answer
- accretion, nobody ever removes
- config.xml records the owning plugin
- unreferenced and unmaintained go first
- uninstalling breaks deserialization
- sometimes rebuild instead of prune
basics
~20 sGrade each plugin by evidence of use, maintenance status and whether a scripted alternative exists. Removal is not free: job configs referencing it stop deserializing, so plan for old-data breakage — and often a curated rebuild beats pruning in place.
solid answer
~50 sFirst measure. Job configuration is XML on disk and records the plugin that owns each element, so grepping `$JENKINS_HOME/jobs/**/config.xml` for `plugin="shortname@version"` tells you what is genuinely referenced; Jenkinsfiles in SCM tell you the rest. Anything with no references and no maintainer goes first. Then judge the remainder on whether the integration is worth a permanent trust grant and a vote on your next core upgrade, or whether a `sh` step calling a vendor CLI, wrapped once in a shared library, would do. The cost of removal is real: uninstalling a plugin whose classes appear in a job's XML leaves data Jenkins cannot deserialize, surfacing under Old Data, and jobs can lose configuration silently. Past a certain age the better move is a curated new controller and a job migration rather than pruning the old one.
code
bash · 6 lines# Rank installed plugins by how many job configs reference them
for p in "$JENKINS_HOME"/plugins/*.jpi; do
name=$(basename "$p" .jpi)
n=$(grep -rl "plugin=\"$name@" "$JENKINS_HOME/jobs" --include=config.xml 2>/dev/null | wc -l)
printf '%5d %s\n' "$n" "$name"
done | sort -ngo deeper
Understand that plugins accumulate over a controller's life and that the count itself is a maintenance problem, not just untidiness.
Be able to gather evidence of use — the owning-plugin attribute in job config.xml, plus step names in Jenkinsfiles — and to say what a bulk uninstall would break.
Sequence the work safely: migrate referencing jobs first, uninstall second, rehearse on a staging copy of JENKINS_HOME, then check old-data and startup warnings.
Take a position on which project this is — prune, rebuild from a curated list, or split into several controllers — and defend it on upgrade coupling, trust surface and migration cost rather than on plugin count.
## Where 200 plugins come from Nobody chooses sprawl. It accretes: the setup wizard's suggested set, transitive dependencies of things people did choose, detached plugins added by core upgrades, a one-off integration for a team that has since disbanded, three overlapping notification plugins from three eras, and a UI plugin somebody trialled in 2018. Nothing removes plugins, so the count only rises. ## Why it matters beyond tidiness - **Upgrade coupling.** Every installed plugin's maintainer holds a partial veto on when you may move core, and one incompatible plugin can block the whole upgrade. - **Trust surface.** Each plugin is standing, unconfined code in the controller JVM, and each is a subscription to that maintainer's future advisories. - **Startup and memory.** Extension scanning and loading are proportional to the set; a bloated controller restarts slowly, which makes every maintenance action more expensive and therefore rarer. - **Migration cost.** Moving to a new controller, a container platform, or another CI system is priced by the plugin set, because each plugin is behaviour with no equivalent elsewhere. ## Measure before you cut Jenkins stores job configuration as XML, and elements contributed by a plugin carry an attribute naming it: ```bash # Which jobs reference the plugin "copyartifact"? grep -rl 'plugin="copyartifact@' "$JENKINS_HOME/jobs" --include=config.xml ``` That gives you real evidence for freestyle and multibranch job configuration. For Pipeline, the usage lives in `Jenkinsfile`s in your repositories, so search SCM for the step names a plugin contributes. Combine both and every plugin lands in one of three buckets: **referenced**, **unreferenced**, or **infrastructure** (a dependency of something referenced, or something that provides behaviour without appearing in configuration — authorization strategies, credential providers, agent clouds). The third bucket is the one that punishes naive automation, so treat "no grep hits" as a lead rather than a verdict. ## The decision, per plugin Ask in order: 1. **Is anything using it?** If not, and it is not infrastructure, remove it. This is usually the largest bucket and the cheapest win. 2. **Is it maintained?** An unmaintained plugin with open advisories is a liability whether or not it is used; that becomes a migration task, not a keep decision. 3. **Would a script do?** A great many plugins wrap an HTTP API or a vendor CLI. A single `sh` step, wrapped once in a shared library so every team calls it the same way, trades a permanent trust grant and an upgrade veto for code you own and can debug. 4. **Does it earn its coupling?** Some do, unambiguously — the SCM plugins, Pipeline, Credentials, and whatever provisions your agents. Nobody should be replacing those with scripts. ## What removal actually costs This is the half candidates skip. Jenkins does not check usage before an uninstall, and it does not rewrite job configuration to compensate. When a plugin goes: - Job XML referencing its classes can no longer be deserialized. Jenkins retains the raw XML and reports the situation under its old-data management page, but the affected configuration is inert — and if you then save that job from the UI, the unreadable parts can be dropped for good. - Jobs can fail to load entirely when the missing element is structural rather than a single build step. - Build history that depended on plugin-provided actions loses those views. So the safe sequence is: identify references, migrate or delete those jobs *first*, uninstall second, restart, then check the old-data report and the controller log for deserialization warnings. Do it on a staging controller restored from a copy of `JENKINS_HOME` before you do it anywhere real. ## When pruning is the wrong project On a controller old enough to have 200 plugins, in-place pruning can cost more than it returns: every removal is a small migration, and the end state is still a hand-made controller nobody can rebuild. The alternative is to stand up a controller built from a curated, pinned plugin list and declarative configuration, then migrate jobs onto it deliberately, leaving the old one read-only until it is retired. You get a known-good baseline and the migration effort buys a reproducible platform rather than a slightly smaller mess. A related structural move is to run **several controllers** with narrow plugin sets — per business unit, or splitting the strictly-governed production-deployment controller from the general build controller. Each stays upgradeable on its own schedule and a bad plugin has a smaller blast radius. The cost is real: more platforms to operate, credentials and agent capacity to arrange per controller, and a shared-library or template story so the split does not fragment practice. ## Answering it in an interview Give the measurement method, the decision criteria, the removal hazard, and — most importantly — a stated position on when pruning is not worth it. The senior answer removes plugins. The principal answer says which of the two projects it actually is, and what the organisation gets for the money.
- How do you find which jobs actually use a plugin before removing it?Grep job configuration for the owning-plugin attribute, `plugin="shortname@version"`, across `$JENKINS_HOME/jobs/**/config.xml`, and search your repositories for the pipeline step names the plugin contributes. Treat zero hits as a lead, not proof — authorization strategies, credential providers and agent clouds provide behaviour without appearing in job XML at all.
- When is standing up a new controller better than pruning the old one?When the plugin set is old enough that each removal is its own small migration and the end state would still be a hand-made controller. Building a fresh one from a pinned plugin list and declarative configuration, then migrating jobs, costs similar effort but leaves you something reproducible. Below that threshold, pruning the obviously-unused plugins is the cheaper win.
- What are the real costs of splitting one controller into several with narrower plugin sets?More platforms to patch, back up and monitor; agent capacity and credentials arranged per controller; and a genuine risk that practice fragments across teams. You buy independent upgrade schedules and a smaller blast radius per plugin. It pays off when teams' needs genuinely diverge, and it is overhead when they do not.
saying these in an interview costs you the question
- Uninstalls plugins in bulk without checking references
- Assumes Jenkins blocks removal of a plugin in use
- Treats zero grep hits as proof nothing needs it
- Counts plugins as harmless if no job uses them
- Proposes pruning without pricing it against a rebuild