MLOpsThe MLOps lifecycle · MLflow 3.17 · DVC 3.67 · FastAPI · Docker · GitHub Actions · Evidently · Python 3.11+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
50 small wins to finish your pathNext lesson →

The model registry

The model registry is a named list of model versions inside MLflow, so the question of which trained model other code should load has one answer that is not a file path.

Last updated: 19 Oct, 2026 · MLOps

The Comparing runs in the MLflow UI lesson found the better of two runs. Something now has to serve it. The video registers each logged model under one name, which creates version 1, then version 2 after the next training run, and marks the version it wants with its lifecycle label. Registering is one call on a logged model's URI, and the label has changed since the video: MLflow 3 marks a version with an alias rather than a stage.

Registering a logged model

Syntax: mlflow.register_model takes a logged model's URI and a registered name. The first call creates the name and version 1; every later call on the same name adds a version.

python
v = mlflow.register_model(model_uri, "student-performance-rf")   # returns the new version
print(v.version)

Pointing MLflow at a local store

The same two required lines open every tracked run: the opt-in MLflow 3.17 wants before it will use a file store, and the tracking URI that names the folder.

python
import os, shutil

os.environ["MLFLOW_ALLOW_FILE_STORE"] = "true"   # 3.17 refuses a local file store without this
shutil.rmtree("mlruns", ignore_errors=True)      # each lesson starts from an empty store
os.makedirs("mlruns/.trash", exist_ok=True)      # MLflow keeps deleted runs in .trash

import mlflow
mlflow.set_tracking_uri("file:./mlruns")
mlflow.set_experiment("student-performance")

Logging both models before registering them

The two configurations are trained and logged as before, and this time each model's URI is kept. fit is the student-performance trainer from the Experiment tracking lesson, and skops_trusted_types is what the Logging a model with MLflow lesson added to save a forest.

python
NAME = "student-performance-rf"
uris = {}

# log both models, keeping each model's URI so it can be registered below
for depth in (12, 4):
    model, scores = fit(max_depth=depth)
    with mlflow.start_run(run_name=f"depth-{depth}"):
        mlflow.log_params({"n_estimators": 100, "max_depth": depth, "random_state": 42})
        mlflow.log_metrics(scores)
        info = mlflow.sklearn.log_model(model, name="model",
                                        skops_trusted_types=["sklearn.tree._tree.Tree"])
    uris[depth] = info.model_uri

Adding versions and pointing an alias at one

Both models go under one registered name, so they become version 1 and version 2 of the same thing. The alias champion is then pointed at the version that won the comparison, which is the depth-12 model.

ExampleTwo versions registered, with champion pointing at the better one
from mlflow.tracking import MlflowClient
client = MlflowClient()

# each call adds a version under the one registered name, newest version last
v12 = mlflow.register_model(uris[12], NAME)
v4 = mlflow.register_model(uris[4], NAME)

# an alias is a movable pointer: champion is the version other code asks for
client.set_registered_model_alias(NAME, "champion", v12.version)

print("versions   :", [int(v.version) for v in client.search_model_versions(f"name='{NAME}'")])
print("champion   :", client.get_model_version_by_alias(NAME, "champion").version)
print("depth-4 is :", v4.version)

What the registry recorded

  • Two versions under one name. The depth-12 model became version 1 and the depth-4 model version 2, numbered by when they were registered rather than by how good they are.
  • search_model_versions lists newest first, so the versions print as 2 then 1.
  • The alias is the answer to which model to load. champion points at version 1, and get_model_version_by_alias resolves it, so serving code asks for the alias and never for a version number.
  • Moving the pointer is the whole deployment. When a better model arrives, the alias is pointed at its version and the code that loads champion changes nothing.
The model registry drawn as one named list. Two runs feed it: the depth-12 run with r2 0.8485 and the depth-4 run with r2 0.8374, each logging a model. Registering them under the name student-performance-rf creates version 1 from the depth-12 model and version 2 from the depth-4 model, numbered by registration order rather than by score. A movable champion alias points at version 1, and serving code loads models colon slash slash student-performance-rf at champion, so promoting a better model later means pointing the alias at another version and changing no code.

Loading by alias

Serving code refers to the alias, not a version. The URI form is models:/student-performance-rf@champion, which mlflow.sklearn.load_model resolves to whatever version the alias points at today.

python
# the serving side asks for the alias, so promoting a model needs no code change
model = mlflow.sklearn.load_model("models:/student-performance-rf@champion")
Seven versions of one registered model, and moving one to production · from the Complete End to End Deep Learning Project With MLFLOW,DVC And Deployment · 2:58:27 to 3:00:00

The clip marks a version by moving its stage from None to Staging to Production; MLflow deprecated model-version stages in 2.9, and 3.17.1 marks a version with an alias instead, which is what this lesson does.

Aliases against the stages the videos use

The 2023 videos mark a version by moving its stage from None to Staging to Production with transition_model_version_stage. That call still runs on 3.17.1 and warns that model registry stages are deprecated and will be removed, pointing at the migration guide. An alias does the same job without a fixed vocabulary: you name the pointer yourself, and a version can carry more than one.

Stages (the videos)Aliases (current)
The calltransition_model_version_stageset_registered_model_alias
Names allowedNone, Staging, Production, ArchivedAny name you choose
Per versionOne stage at a timeSeveral aliases possible
Status on 3.17.1Deprecated, warns on useThe documented way

Where the registry sits in a project

  • Serving, where the API loads champion at startup and knows nothing about runs.
  • Promotion, where a candidate is registered, tested, and then becomes champion by one call.
  • Audit, where every version still points back at the run, its parameters and its metrics.
Watch out. A version number is not a quality ranking. Version 2 here is the worse model, because versions are numbered by registration order. Code that loads the latest version gets whatever was registered last, which is why serving code loads an alias.
Try it yourself
  • Point champion at version 2, resolve the alias again and watch the version it returns change.
  • Add a second alias such as candidate on version 2 and list the aliases of that version.
  • Load models:/student-performance-rf@champion and score it on the test set to confirm you get r2 0.8485.

Little by little, you're building something great.