unity catalog

GuideUse Unity CatalogModels

Manage registered models

Register MLflow models as Unity Catalog model versions, load a version by number, and update, rename, and delete models and versions.

A registered model in Unity Catalog lives in a schema and has a three-level name, such as unity.manage_models.linear. It holds numbered versions, and each version has its own copy of the model's files in the catalog's managed storage. MLflow's tracking server keeps the runs and the logged models. Unity Catalog keeps the registered models and their versions (how the two services divide the work).

On this page, MLflow uploads a version's files and loads them. MLflow, the Python SDK, and the CLI all view, update, and delete models and versions, and only the SDK and the CLI rename them.

Each task lists the privileges that the server's authorization rules for models require when authorization is enabled.

Set up the client

Set up the client for your interface:

Start Python with MLflow, boto3 for the version's files in S3, and scikit-learn, the library the example model uses:

uv run --python 3.12 --with mlflow==3.17.0 --with boto3==1.43.114 --with scikit-learn==1.9.1 python

Point MLflow at the tracking server and at Unity Catalog's registry. The uc: prefix on the registry URI selects MLflow's Unity Catalog registry, and AWS_ENDPOINT_URL_S3 points MLflow at the environment's S3-compatible store. The MLFLOW_ENABLE_PROXY_MULTIPART_* settings keep the logged model's files going through the tracking server, whose download links name an address only the environment can reach:

models_mlflow.pyFull script
import os

import mlflow
from mlflow import MlflowClient

os.environ["AWS_ENDPOINT_URL_S3"] = "http://localhost:9000"
os.environ["MLFLOW_ENABLE_PROXY_MULTIPART_DOWNLOAD"] = "false"
os.environ["MLFLOW_ENABLE_PROXY_MULTIPART_UPLOAD"] = "false"
mlflow.set_tracking_uri("http://localhost:8080")
mlflow.set_registry_uri("uc:http://localhost:8080")
client = MlflowClient()

The examples use one model, unity.manage_models.linear. The next section registers it with versions 1 and 2, and every section after it starts from there.

Register a model version

Registering needs a model logged in MLflow. To follow along, train two small linear models, y = 2x + 1 and y = 3x + 1, and log each in its own run:

models_mlflow.pyFull script
import pandas as pd
from mlflow.models import infer_signature
from sklearn.linear_model import LinearRegression

X = pd.DataFrame({"x": [0.0, 1.0, 2.0, 3.0, 4.0]})
mlflow.set_experiment("manage-models")
model_uris = []
for slope in (2, 3):
    fitted = LinearRegression().fit(X, slope * X["x"] + 1)
    with mlflow.start_run():
        info = mlflow.sklearn.log_model(
            fitted,
            name="linear",
            signature=infer_signature(X, fitted.predict(X)),
            pip_requirements=["mlflow==3.17.0", "scikit-learn==1.9.1"],
        )
    model_uris.append(info.model_uri)

print(model_uris)

The session prints the two logged models' URIs, each of the form models:/m-<id>.

Register the first one under the model's name. If the model doesn't exist, MLflow creates it with version 1:

models_mlflow.pyFull script
version = mlflow.register_model(model_uris[0], "unity.manage_models.linear")
print(version.version, version.status)

MLflow reports:

Successfully registered model 'unity.manage_models.linear'.
Created version '1' of model 'unity.manage_models.linear'.
1 READY

Register the second one under the same name. MLflow adds the next version:

models_mlflow.pyFull script
version = mlflow.register_model(model_uris[1], "unity.manage_models.linear")
print(version.version, version.status)
Registered model 'unity.manage_models.linear' already exists. Creating a new version of this model...
Created version '2' of model 'unity.manage_models.linear'.
2 READY

Both calls also print a line about waiting for the version and progress bars. One call creates the version, copies the logged model's files into the catalog's managed storage, and marks the version READY. MLflow writes the files with temporary credentials that Unity Catalog issues for that one version. See Credential vending.

MLflow doesn't pass tags to Unity Catalog. Tags given to register_model or create_registered_model are dropped without an error.

Required privileges: mlflow.register_model tries to create the model first and continues only if it already exists, so every call needs all of these:

  • To create the model, even when it exists: USE_CATALOG or ownership on the catalog, and on the schema either ownership, or USE_SCHEMA plus CREATE_MODEL (or CREATE_FUNCTION). Whoever creates the model owns it.
  • To add and finalize the version: ownership of the catalog; or USE_CATALOG and ownership of the schema; or USE_CATALOG, USE_SCHEMA, and ownership of the model.
  • To write the version's files: ownership of the model, plus USE_SCHEMA or ownership on the schema and USE_CATALOG or ownership on the catalog. Owning the catalog doesn't replace owning the model.

View models and versions

models_mlflow.pyFull script
for model in client.search_registered_models():
    print(model.name, model.description)

for v in client.search_model_versions("name='unity.manage_models.linear'"):
    print(v.version, v.status, v.source)

Search takes no filter_string or order_by for models, and no order_by for versions. Either one raises Argument '…' is unsupported for models in the Unity Catalog.

A version's status is READY once registration finishes. Its source is the logged model it was copied from, models:/m-<id>. Its run_id is set only when you register from a runs:/<run-id>/<path> URI. A model's storage_location is a directory in the catalog's managed storage, and each version's files sit below it, under versions/.

Required privileges: one of ownership of the metastore; ownership of the catalog; USE_CATALOG and ownership of the schema; or EXECUTE or ownership on the model, plus USE_SCHEMA and USE_CATALOG. A list of models returns only the models you could get.

Load a model version

Load a version by its number, and get the location of its files:

models_mlflow.pyFull script
model = mlflow.pyfunc.load_model("models:/unity.manage_models.linear/1")
print(model.metadata.signature)
print(model.predict(pd.DataFrame({"x": [10.0]})))
print(client.get_model_version_download_uri("unity.manage_models.linear", "1"))

The session prints the version's signature, with the input column x as a double, then the prediction [21.], since version 1 fits y = 2x + 1. The signature comes from the version's files, not from Unity Catalog's record of the version. The location has the form s3://amzn-s3-demo-bucket/unity/__unitystorage/catalogs/<id>/models/<id>/versions/<id>. MLflow reads the files with read-only credentials from Unity Catalog.

Load by number only. Unity Catalog's registry has no aliases and no stages, so models:/<name>@<alias> and models:/<name>/latest raise NotImplementedError: Method not implemented. So do setting an alias, get_latest_versions, and transition_model_version_stage.

Required privileges: the privileges to view the version, and to read its files, EXECUTE or ownership on the model, plus USE_SCHEMA or ownership on the schema and USE_CATALOG or ownership on the catalog. Owning the catalog or the metastore doesn't replace these.

Update comments

Besides the model's name, a comment is the only metadata you can change on a model or a version. Set one on the model and one on version 2:

MLflow calls the comment description:

models_mlflow.pyFull script
client.update_registered_model(
    "unity.manage_models.linear",
    description="Predicts y from x with a linear fit",
)
client.update_model_version(
    "unity.manage_models.linear", "2", description="Retrained on the new slope"
)

The Python sessions echo the updated model and version. Other versions keep their comments. Models and versions have no tags: set_registered_model_tag and set_model_version_tag raise NotImplementedError. A version's signature and input example live in its files, not in Unity Catalog.

Required privileges: one of ownership of the catalog; USE_CATALOG and ownership of the schema; or USE_CATALOG, USE_SCHEMA, and ownership of the model. The same holds for a model's comment and a version's.

Rename a model

Rename a model with the Python SDK or the CLI. new_name is the model's name within its schema. MLflow's rename_registered_model raises NotImplementedError.

The example renames the model to linear_regression and prints the result, then renames it back, so the examples below still find it as linear:

models_sdk.pyFull script
renamed = await models.update_registered_model(
    full_name="unity.manage_models.linear",
    update_registered_model=UpdateRegisteredModel(new_name="linear_regression"),
)
print(renamed.full_name)

# Rename it back, so the steps below find it by its first name.
await models.update_registered_model(
    full_name="unity.manage_models.linear_regression",
    update_registered_model=UpdateRegisteredModel(new_name="linear"),
)

The model keeps its id, storage location, comment, and versions. Only its name changes.

Required privileges: the same as for updating a comment.

Delete versions and models

Required privileges: to delete a version, or a model with or without force, the same as for updating a comment.

Delete a version

models_mlflow.pyFull script
client.delete_model_version("unity.manage_models.linear", "2")

Delete a model

A model that still has versions is deleted only with force. Without it, the server refuses with Unable to delete a registered model with existing model versions. The Python SDK and the CLI pass force. MLflow can't, so its example deletes the versions first, a page of search results at a time, until none are left:

models_mlflow.pyFull script
name = "unity.manage_models.linear"
while versions := client.search_model_versions(f"name='{name}'"):
    for v in versions:
        client.delete_model_version(name, v.version)

client.delete_registered_model(name)

What happens to the files

The catalog entry goes at once. A background worker in the server deletes the version's or the model's directory in managed storage no sooner than server.storage-cleanup.initial-delay after the delete, 7 days by default, and retries a deletion that fails. The run and the logged model on the MLflow tracking server, with their files, stay.

Next steps