skip to content

Twelve teams each maintain their own Helm charts. Would you standardise them on one shared library chart?

level: principalimportance: should knowfreq 26%

answer

  1. Share invariants, not workload shape
  2. A shared chart has consumers
  3. Exported helper names are public interface
  4. Render diffs are the real changelog
  5. Adoption needs automation, not goodwill

basics

~20 s

Share only the invariants - labels, naming and truncation, image references - and leave workload shape to each chart. A shared library is a product with consumers: it needs an owner, semver, render-diff contract tests and automated bumps.

solid answer

~50 s

Yes for the cross-cutting pieces that must be identical for the platform to work, no for the shape of anyone's workload. A library chart that exports label blocks, name truncation and image reference helpers pays for itself the first time a platform-wide label changes. A library chart that exports whole Deployments has quietly become a generic chart with extra steps: every consumer is coupled to your object shape, and the first team that needs a field you did not template forks. Whatever you share, treat it as a product - one owning team, semver where an exported helper name is public interface, a CI job that renders every consumer against the candidate version and diffs the output, and automation that opens the bump pull requests. Without adoption pressure you end up supporting several library versions at once, which is worse than the duplication you set out to remove.

go deeper

for a junior

Know that shared helpers exist so a change is written once, and that the cost is a version bump in every chart that uses them. You are not expected to make the call.

for a middle

Be able to argue what belongs in a shared library - labels, naming, image references - and what does not, and to say why a library that renders whole objects couples its consumers too tightly.

for a senior

Demonstrate the operational side: contract tests that diff every consumer's render against a candidate version, automated bump pull requests, and a way to see which releases are still behind.

for a principal

Own the tradeoff explicitly. Say what you would standardise, what you would deliberately leave duplicated, who owns the artefact, how a breaking change is sequenced, and what signal would make you abandon the library.

### What you are actually choosing between Three shapes compete here, and naming them separates the decision from the tooling. Duplication: every team keeps its own helpers. Cheap to start, zero coupling, and drift is guaranteed - a change to the standard label block is twelve independent edits, and you will discover the two nobody made during an incident. A shared library chart: helpers are authored once, versioned, and pulled in as a dependency. The change is written and reviewed once; adoption is still twelve version bumps, but they are mechanical and reviewable. One generic application chart everyone installs: centralises the most - a single chart version, one place to change anything - but it forces every workload into one templated shape and one release cadence, and every unusual requirement becomes a new values key on a chart that grows without bound. This is a different decision from how you slice releases; it is about who owns the object definitions. ### Where the line goes Share what must be identical for the platform to function, not what merely looks similar. Standard labels and selector construction, name truncation rules that keep generated names inside length limits, image reference assembly from registry, repository and tag, and any annotation your tooling reads: these are invariants, and a divergence in them is a platform bug. Share those. Do not share the workload. The moment a library exports a complete Deployment, its consumers stop owning their own objects. Every field somebody needs and you did not expose becomes a values key on your chart, and the team that cannot wait forks. You will also have made every consumer's rendered output change whenever you touch that template, which turns a helper bump into a fleet-wide risk. A useful test: if a consumer could reasonably want the helper's output to differ, it is not an invariant and does not belong in the library. ### Running it as a product A shared library with twelve consumers has consumers, and every consumer property applies. Ownership: one team is accountable, and the library has a changelog. A library everyone may commit to and nobody owns accumulates helpers nobody can safely remove. Interface discipline: the set of exported names is public API. Renaming an exported helper, or changing what context one expects, is a breaking change; give it a major version and a deprecation window in which both names exist. Consumers cannot adopt on your schedule, so give them one they can meet. Contract testing: keep a job that, for each consumer chart, renders it against the current library and against the candidate version and diffs the YAML. That diff is the real changelog. A library change whose diff across twelve charts is empty is safe by construction; one that changes a selector should stop the release, because a selector change lands as an immutable-field failure at upgrade time in someone else's namespace. Adoption: automate the bump pull requests. Adoption that depends on twelve teams choosing to do it produces a long tail on old versions, and a long tail means you are effectively maintaining several libraries. ### The failure modes worth naming up front The library becomes a bottleneck: any chart change requires a library release, so teams stop asking and copy the helper back into their own chart. That is the signal the boundary was drawn too wide. The library freezes: it has enough consumers that nobody will accept a breaking change, so it grows a second way to do everything. Cap this by budgeting for majors and by keeping the exported surface small - a small surface is what makes a major version survivable. Nobody knows who runs what: without an emitted version label you cannot answer "which namespaces still render the old block", and the migration has no end condition. ### The honest answer in an interview Start with the invariants, ship a deliberately small library, and let it grow only when the same helper has been copied twice. Measure success by whether a platform-wide change - one added label across a 12-namespace fleet - is one authored change plus mechanical bumps, rather than twelve hand-edits. If the library cannot deliver that, it is coupling without the payoff, and duplication was the better trade.

  • What would make you split one library chart into several?
    Different consumer sets and different change rates. If half the helpers are used by every chart and half only by the two data services, one library forces the whole fleet to absorb releases it does not care about. Splitting keeps each library's blast radius equal to its actual audience, at the cost of another artefact to version.
  • How do you retire a helper nobody should call any more?
    Keep it, make it emit the same output, and find the callers - a render-based scan across consumer charts, or a search across repositories. Announce it in the changelog, remove it only in a major version, and drive the remaining consumers with automated pull requests. Deleting an exported name in a minor breaks renders in namespaces you do not operate.
  • When would you say no to a library chart entirely?
    When there are two or three charts, when the teams have no shared platform invariants worth enforcing, or when nobody will own the artefact. Below a handful of consumers the coordination cost of a versioned dependency exceeds the cost of the duplication it removes.

saying these in an interview costs you the question

  • Puts whole Deployment templates in the shared library
  • Treats a helper rename as a non-breaking change
  • Assumes twelve teams will adopt without automation
  • Has no owner for the shared chart
  • Measures success by lines of duplication removed

context