System Design · step by stepDesign a Model Registry
Step 1 / 9

Design a Model Registry (MLOps) — the walkthrough in full

A written version of the interactive walkthrough above — the same steps, decisions and trade-offs, laid out for reading, reference and search.

The big idea

The gap between "it trained" and "it's safely serving"

A model finishes training. Turning that into a file that answers real production requests safely is a genuinely different problem than training it — versioning, validating, gradually rolling out, and being able to instantly undo it if something's wrong. Skip this layer and "which model is actually in production, and can we prove it's the one we validated" becomes an unanswerable question.

We'll build the governance layer: immutable versioning with full lineage, staged promotion through validation gates, shadow/canary deployment because offline metrics alone aren't enough, instant rollback, and ongoing production drift monitoring.

How to read this: Each step opens with a real design decision — make the call before I show you what ships. Watch the diagram grow, hover the boxes, and at the end kill the eval gate and trigger production drift to see the safety mechanisms actually engage. Hit Begin.

Step 1 · The baseline

A file gets deployed

Simplest version: someone trains a model, copies the resulting weights file to wherever the serving system reads from, and it's live. What breaks down as this scales beyond one person, one model?

Design decision: Model files get deployed ad-hoc, with no registry or tracked lineage. What's the core problem?

The call: Nobody can reliably answer "which exact model version is currently serving," "what data/code/hyperparameters produced it," or "how do we get back to the previous one" — a reproducibility and rollback blind spot. — Without a registry and tracked lineage, the model in production is effectively an untraceable artifact: if it starts behaving badly, there's no reliable record of what to roll back TO, and no way to reproduce or audit exactly how it was trained.

Without a registry, nobody can reliably answer which model version is live, what produced it, or how to get back to a known-good state if it fails — a reproducibility and rollback blind spot that gets worse with every additional model and every additional engineer.

A model artifact alone is nearly meaningless: Weights without lineage (what data, what code, what hyperparameters) can't be debugged, audited, or safely reproduced — the metadata around a model is often as operationally important as the model itself.

Step 2 · Immutable versioning and lineage

Every model, tagged with what produced it

Fix the blind spot with a registry.

Introduce a Model Registry backed by Versioned Artifacts storage: every trained model is registered as an immutable version, tagged with exactly which training data version, code commit, and hyperparameters produced it. Past versions are never overwritten — a new training run is always a NEW version, never a mutation of an old one.

Immutability is what makes everything downstream possible: Rollback (Step 6), reproducibility (Step 7), and safe comparison during evaluation (Step 4) all depend on past versions being permanently, immutably available — the moment a version can be overwritten, all three of those guarantees break.

Step 3 · Staged promotion

Dev → staging → production, not a straight line

A newly-registered model version exists. Should it be eligible to serve production traffic immediately?

Design decision: A model just finished training and got registered. Should it be immediately eligible to serve production traffic?

The call: No — a model progresses through explicit stages (dev, staging, production), each gated by validation, before it's eligible to actually serve real traffic. — Staged promotion means a model has to earn its way to production through explicit checkpoints, rather than a successful training run alone being sufficient — this mirrors how a code change progresses through environments before reaching users.

Give every model version an explicit stage tracked by the registry — dev, staging, production — and require an explicit, gated promotion action to advance between them. A model doesn't default into serving production traffic just by existing; it has to be deliberately promoted, with checks along the way.

Explicit stages, explicit gates: The same staged-environment pattern used for code deployment (dev → staging → prod) applies to models, with the added twist that "does this pass" for a model isn't just "does the code run" — it's "does this model perform at least as well as what's currently live," which needs actual evaluation, not just a successful build.

Step 4 · Automated evaluation gate

Block promotion on regression, automatically

Before a candidate model can be promoted, it should be validated against the currently-serving model. Should that validation be a manual, ad-hoc judgment call each time?

Design decision: A candidate model needs validation before promotion. Manual judgment call, or something else?

The call: An automated Eval Gate that runs the candidate against a held-out evaluation set, computes the same metrics (accuracy, latency, relevant fairness checks) for both the candidate and the currently-serving baseline, and blocks promotion automatically if the candidate regresses. — Automating the gate makes validation consistent, fast, and impossible to accidentally skip — every promotion attempt runs the same objective comparison against the current production baseline, and a regression is blocked by default rather than relying on someone remembering to check.

Add an automated Eval Gate: every promotion attempt runs the candidate against a held-out evaluation set, computes the same metrics for the candidate and the current production baseline, and blocks promotion by default on any meaningful regression. This makes validation consistent and impossible to skip under pressure.

Automate the check that must never be skipped: A safety check that depends on someone remembering to run it manually, especially under deadline pressure, will eventually be skipped. Automating it — and making the DEFAULT outcome "blocked" rather than "allowed" — removes that human-reliability failure mode entirely.

Step 5 · Shadow and canary deployment

Offline metrics aren't the whole story

The candidate passed the Eval Gate against a held-out dataset. Is that sufficient confidence to fully replace the production model right now?

Design decision: A candidate passed offline evaluation against a held-out set. Is that enough to fully deploy it to 100% of production traffic?

The call: No — run the candidate in shadow (mirrored live traffic, results not shown to users) or as a small canary (a small percentage actually served) first, to observe real-world behavior before it fully replaces the current model. — Shadow/canary deployment exposes the candidate to actual current production traffic — the real distribution, not a static historical snapshot — while limiting user-facing risk to zero (shadow) or a small, bounded slice (canary). This catches real-world behavior gaps that a held-out offline eval set, by definition, can't.

Run the candidate through Shadow or Canary deployment before full promotion: shadow mode mirrors live traffic to the candidate with results never shown to users (zero risk, real data); canary mode actually serves a small percentage of real traffic (bounded risk, real user-facing signal). Only after this real-world validation does the candidate earn full production promotion.

Offline eval and online validation catch different things: A held-out dataset is a fixed snapshot; production traffic is a live, shifting distribution. Passing the former is necessary but not sufficient — shadow/canary is what actually validates behavior against the real, current world the model will operate in.

Step 6 · Rollback

A version pointer, not a fire drill

The new model is fully promoted and serving. Something's wrong in production that wasn't caught earlier. How fast can you get back to the previous version?

Because every past version is immutably stored in Versioned Artifacts, rollback is simply repointing production serving at the previous version id — no retraining, no re-deriving what the old model was, because it was never overwritten in the first place. This is the direct payoff of the immutability decision made back in Step 2.

Rollback speed is a direct consequence of immutability: If versions could be overwritten, rolling back would require somehow reconstructing what the previous model was — often impossible. Because Step 2 made every version permanent, rollback degrades to "change which version id is currently serving," a fast, low-risk operation.

Step 7 · Reproducibility and audit

Prove exactly what produced this model

Months later, someone needs to know exactly how the currently-serving model was produced — for debugging an issue, or for a compliance/audit requirement.

Because every version's lineage (training data version, code commit, hyperparameters) was recorded at registration time, the registry can answer exactly what produced any given model version — and, with the same data and code pinned by hash/version rather than "latest," the training run can genuinely be reproduced if needed. This lineage record is often as important operationally as the model weights themselves.

Pin references, don't point at "latest": Recording "trained on the current version of the dataset" is nearly useless months later if that dataset has since changed — lineage has to reference an immutable, specific version of every input (data, code, config), not a moving target.

Step 8 · Production drift

Valid at deploy time isn't valid forever

A model passed every gate and is performing well in production. Six months later, has anything changed?

Design decision: A model passed every validation gate at deploy time. Does that guarantee it stays good indefinitely?

The call: No — the world the model operates in keeps changing after deployment, so production performance needs ongoing monitoring, not just a one-time deploy-time check. — Deploy-time validation only proves the model was good AT THAT MOMENT, against data available then. A Drift Monitor watching the SERVING model's real-world performance continuously is what catches gradual degradation that no amount of pre-deployment gating could have predicted.

Add a Drift Monitor watching the currently-serving model's real-world performance continuously — not just at deploy time. When production metrics degrade meaningfully from their validated baseline, it flags the registry, triggering either an automatic rollback to the previous known-good version (Step 6) or an alert for human review, depending on the severity and the organization's risk tolerance for that model.

Design for the unhappy path: Eval gate down → fail closed, no unvalidated promotion. Bad production model → immutable versioning makes rollback a version pointer, not a fire drill. Silent drift → ongoing monitoring, not just a deploy-time check. A registry that only works for models that stay good forever after deployment is a demo; one that catches and recovers from real-world drift is a product.

You did it

You just designed a model registry.

  • A
  • I — m
  • M — o
  • A — n
  • S — h
  • R — o
  • O — n
built so rolling back a bad model is a version pointer, not a fire drill — make the calls, kill the eval gate, run the gauntlet.
Finished this one? 0 / 54 AI System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More AI System Designs