1.15 Model Tags, Aliases, and Champion/Challenger Promotion

Key Takeaways

  • `client.set_registered_model_alias(name, alias, version)` points a named alias at a version; `delete_registered_model_alias(name, alias)` removes it.
  • An alias is a mutable pointer and is exclusive: assigning `@champion` to a new version automatically moves it off the previous one.
  • Tags are descriptive key/value metadata set with `set_model_version_tag` and removed with `delete_model_version_tag`; unlike aliases, many versions can carry the same tag.
  • Aliases replace the legacy stages `None`, `Staging`, `Production`, and `Archived`, which do not exist for models in Unity Catalog.
  • Loading by alias — `models:/catalog.schema.model@champion` — lets promotion happen with zero changes to downstream client code.
Last updated: August 2026

1.15 Model Tags, Aliases, and Champion/Challenger Promotion

Legacy MLflow gave every model version one of four fixed stages. Unity Catalog removes them and provides two orthogonal mechanisms instead: aliases, which are exclusive named pointers used for routing, and tags, which are non-exclusive labels used for description and search.


Managing Lifecycle: Model Aliases and Tags vs. Legacy Stages

In legacy MLflow, models used hardcoded stages (Staging, Production). Unity Catalog deprecates stages in favor of Model Aliases and Tags, providing vastly greater deployment flexibility:

+---------------------------------------------------------------------------------------------------+
|                                MODEL ALIASING AND TAGGING PATTERN                                 |
+---------------------------------------------------------------------------------------------------+
| Model Version 2 <--- Assigned Alias `@champion` (Points production scoring queries here)           |
| Model Version 3 <--- Assigned Alias `@challenger` (Points canary/A-B evaluation queries here)      |
| Model Version 3 <--- Assigned Tag   `validation_status: approved_by_risk_team`                    |
+---------------------------------------------------------------------------------------------------+

Aliases act as mutable named pointers: setting one on a new version automatically removes it from the previous version, so promotion never needs a separate "demote" call. Tags are independent key/value metadata that stay attached to the version that carries them. The consolidated example below exercises both APIs together.


Aliases vs. Tags: the Distinction That Decides Answers

AliasTag
ShapeA name pointing at exactly one versionA key/value pair on a version (or on the registered model)
ExclusivityOne version per alias; reassigning moves itAny number of versions may share a tag
PurposeRouting — "which version should production load?"Description and search — "which versions passed risk review?"
Set withclient.set_registered_model_alias(name, alias, version)client.set_model_version_tag(name, version, key, value)
Remove withclient.delete_registered_model_alias(name, alias)client.delete_model_version_tag(name, version, key)
Referenced in a URIYes — models:/cat.sch.model@championNo
from mlflow.tracking import MlflowClient

client = MlflowClient()
name = "prod_catalog.fraud_detection.payment_risk_classifier"

# Tags: descriptive, non-exclusive
client.set_model_version_tag(name, version=3, key="risk_review", value="approved")
client.delete_model_version_tag(name, version=1, key="risk_review")

# Aliases: exclusive routing pointers
client.set_registered_model_alias(name, alias="challenger", version=3)
client.set_registered_model_alias(name, alias="champion", version=3)   # moves off v2
client.delete_registered_model_alias(name, alias="challenger")

The Champion/Challenger Promotion Workflow

  1. A retraining job registers version 3 and sets @challenger on it.
  2. An automated validation job loads models:/…@challenger and models:/…@champion, scores both on a frozen holdout set, and compares.
  3. If the challenger wins, the job tags the version (validation="passed", promoted_on="2026-08-19") and calls set_registered_model_alias(..., "champion", 3). The alias moves off version 2 automatically; no downstream code changes.
  4. The @challenger alias is deleted so the next cycle starts clean. Version 2 remains in the registry with its tags intact, so rollback is a single alias reassignment.

Because serving endpoints and batch jobs reference the alias rather than a version number, promotion and rollback are metadata operations — nothing is redeployed.

Resolving an Alias and Rolling Back

Automation regularly needs to know which version an alias currently points at — to log it, to score against it, or to roll back to it:

mv = client.get_model_version_by_alias(
    name="prod_catalog.fraud_detection.payment_risk_classifier",
    alias="champion",
)
print(mv.version, mv.run_id, mv.tags)

Rollback is then a single reassignment pointing @champion back at the previous version number. Nothing is rebuilt, no endpoint is recreated, and every job or endpoint referencing models:/…@champion picks the change up on its next model resolution. Recording the outgoing version as a tag — previous_champion="4" — before promoting turns that rollback into a one-liner instead of an archaeology exercise.

Two Levels of Tag

Tags exist on both the registered model and each individual version, and the distinction is testable:

ScopeAPIUse for
Registered model — all versionsclient.set_registered_model_tag(name, key, value)Ownership, business domain, on-call team
A single versionclient.set_model_version_tag(name, version, key, value)Validation outcome, approval reference, promotion date

Naming and Scope Rules

  • A Unity Catalog model is always addressed by a three-level name, catalog.schema.model. A two-level name is a workspace-registry model, where aliases are unavailable and the legacy stages still apply.
  • Aliases are scoped to one registered model, so @champion on prod.fraud.risk_model is unrelated to @champion on prod.churn.propensity.
  • Because an alias is exclusive there is nothing to disambiguate at load time: it resolves to exactly one version, or the load fails.

Loading Models for Batch and Real-Time Inference

Applications can load models from Unity Catalog deterministically by specifying either an Alias or an exact Version Number:

import mlflow.pyfunc

# 1. Load production model dynamically using Alias (Zero code change when champion updates)
champion_uri = "models:/prod_catalog.fraud_detection.payment_risk_classifier@champion"
production_model = mlflow.pyfunc.load_model(champion_uri)
predictions = production_model.predict(inference_pandas_df)

# 2. Load exact pinned model version for reproducible auditing
version_uri = "models:/prod_catalog.fraud_detection.payment_risk_classifier/2"
audit_model = mlflow.pyfunc.load_model(version_uri)

# 3. Load model as PySpark UDF for high-throughput distributed batch scoring
import mlflow.pyfunc
predict_udf = mlflow.pyfunc.spark_udf(spark, champion_uri, result_type="double")
scored_df = spark_features_df.withColumn("fraud_probability", predict_udf(*feature_cols))
Loading diagram...
Model Lifecycle and Promotion with Unity Catalog Aliases
Illustrative canary split: share of scoring traffic by alias
Test Your Knowledge

In Unity Catalog Model Governance, what mechanism replaces legacy MLflow Stage Transitions (such as transitioning a model to 'Production' or 'Staging')?

A
B
C
D
Test Your Knowledge

An MLOps engineer wants to point the '@champion' alias of a registered model 'prod_catalog.ml.churn_model' to Version 4. What code achieves this?

A
B
C
D
Test Your Knowledge

A governance team wants to mark every model version that has cleared its compliance review, while a serving endpoint must always load whichever single version is currently approved for production. Which mechanisms fit these two needs?

A
B
C
D