skip to content

Your organisation has forty repositories with near-identical Jenkinsfiles. How do you decide what moves into a Jenkins shared library and what stays in each repository?

level: principalimportance: nice to knowfreq 30%

answer

  1. reuse is not the goal by itself
  2. same, stable, and owned
  3. the parameter list is the smell
  4. one call per repo costs comprehension
  5. forty consumers means an API

basics

~20 s

Extract logic that is genuinely identical, stable, and organisationally mandated — publishing, notification, scanning, credential wiring. Leave anything repository-specific or fast-changing in the Jenkinsfile, and keep enough visible there that an engineer can still read what their build does.

solid answer

~50 s

I look for three properties before extracting anything: the logic is the same in most repositories, its interface is stable enough to version, and someone will own it. Organisation-wide concerns — how artifacts are published, which scanners run, how failures are announced, how credentials are bound — meet all three. Repository-specific build commands, paths, and anything a team tunes weekly do not; forcing those through a library parameter just moves the variation into an ever-growing options map. I also resist the endgame where every Jenkinsfile becomes a single `standardPipeline()` call: it maximises reuse and minimises comprehension, and the first legitimate exception turns into a flag, then a flag on a flag. My preferred shape is a small set of well-named steps with documented parameters, each doing one recognisable thing, so a Jenkinsfile reads as a short recipe. And I budget for the ongoing cost — versioning, tests, a deprecation path, and someone to answer questions — because a library with forty consumers is a product, not a refactor.

go deeper

for a junior

Know that a shared library exists so common pipeline logic is written once, and that your Jenkinsfile calls its steps rather than repeating the code.

for a middle

Be able to argue which parts of a Jenkinsfile are genuinely common and which are project-specific, and explain why a step with many optional parameters is a warning sign.

for a senior

Talk about the library as a versioned dependency: stable step contracts, documentation, tests, a canary consumer, and a staged migration across consuming repositories.

for a principal

Own the strategy and its costs — the framework-versus-toolkit choice, the escape hatches, who may contribute given the trust model, and how you deprecate a step forty teams call.

## Start from why the duplication hurts Forty copies of a Jenkinsfile is only a problem in the ways it actually bites: a security requirement that must be added forty times, a publish procedure that drifted so that three repos publish differently, an engineer who cannot tell which copy is canonical. Extraction should target those pains specifically. Duplication that nobody has had to change is cheap; the goal is not zero repetition. ## Three tests before extracting **1. Sameness.** Is the logic identical in most consumers today, or identical only if you squint and add parameters? A step needing six parameters to serve four callers is usually four different behaviours wearing one name. **2. Stability of the contract.** A `vars` step's name and parameters become an API for forty repositories. If the shape changes monthly, every change is a fleet migration. Extract the parts whose interface you can commit to for a year. **3. Ownership.** Someone must review changes, cut releases, answer questions, and handle the incident when the library breaks the fleet. Without a named owner, the library becomes an unmaintained dependency everyone is afraid to change. ## What almost always belongs in the library - Organisational policy that must be uniform: mandatory scanning, artifact publication with the right metadata, provenance or audit records. - Credential wiring — the correct credential IDs and binding pattern, so teams never hand-roll secret handling. - Complicated interactions with internal systems: registries, ticketing, deployment services. - Notification and reporting formats, so every team's failure output looks alike. ## What usually stays in the repository - The build and test commands themselves. They are the project's identity and change with the project. - Anything a team iterates on frequently — an extra stage during a migration, a temporary retry. - Choices with genuine local variation: agent labels, timeouts, which environments this service even has. - Anything genuinely trivial. A three-line step that saves nobody time still costs a version bump to change. ## The framework trap The strongest gravity in this area pulls toward a single call per repository. A `vars` file *can* define an entire Declarative pipeline, so `standardPipeline(language: 'java')` is technically possible and initially delightful: forty Jenkinsfiles become forty one-liners. The costs arrive later. Engineers cannot read what their build does; debugging means reading Groovy in another repository they may not have access to. Every legitimate difference becomes a flag, and flags multiply combinatorially. Changing the framework changes forty pipelines at once, so the owning team becomes cautious, and the library ossifies exactly when it is most depended on. If you go that way, design the escape hatches first: hooks for extra stages, a documented way to bypass the framework entirely, and a policy that a repository may fork out when the abstraction stops fitting. ## Structure the library so it can evolve Keep the public surface — the `vars` steps — small and thin, and put the substance in `src/` classes that are unit-testable and free to change. Document each step in the accompanying `.txt` file, because callers will not read the source. Version with tags and treat parameter changes as breaking. Deprecate loudly: keep the old step, have it warn and name its replacement, and remove it only in a new major version. ## Governance choices to state explicitly - **Trust and scope.** A globally trusted library gives its authors controller-level power, so the more teams that contribute, the stronger the case for folder-scoped libraries or an untrusted global one. - **Contribution model.** Central team owns and reviews everything, or teams contribute with the platform team as maintainer? The second scales better and needs stricter review, since trusted code is unsandboxed. - **Migration cost.** Every extraction has a one-off cost across forty repositories. Sequence it: highest-pain concern first, canary repository, then the rest. ## The answer that lands Say that reuse is not the goal — reducing the cost of the changes you actually have to make is. Name the three tests, name what you would leave alone, and be explicit that a shared library is a versioned dependency with consumers, an owner, tests, and a deprecation policy. Interviewers at this level are checking whether you would build a platform someone else can live with.

  • A shared library step has grown to twelve optional parameters. What does that tell you?
    That it is serving several distinct behaviours under one name. The usual remedy is to split it into steps that each mean something, or to move the variation back into the calling repositories where it is visible. Adding a thirteenth parameter keeps callers working but makes the step impossible to reason about or to change safely for anyone.
  • How do you make a fleet-wide extraction land without forty simultaneous pull requests?
    Ship the step first, migrate a canary repository, then move consumers in waves, keeping the old inline code working throughout. Where the library is implicitly loaded and the behaviour must be universal, you can enable it centrally — but only after the canary period, and with a documented way for a repository to opt out while it adapts.
  • When is leaving duplicated Jenkinsfile logic the right call?
    When the logic is short, changes rarely, and differs a little between repositories anyway. The cost of a library is versioning, review, testing and a support burden; if the duplication has not forced a coordinated change in a year, extracting it buys tidiness and sells away local autonomy and readability.

saying these in an interview costs you the question

  • Treats any duplication as a defect to eliminate
  • Collapses every Jenkinsfile into one framework call
  • Adds a parameter whenever a consumer differs
  • Extracts logic with no owner or release process
  • Ignores the migration cost across consuming repositories

context