Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Unity Catalog is the recommended storage location for MLflow traces. This page covers two migration paths:
- Experiment storage → Unity Catalog: if your traces are stored in an MLflow experiment (the legacy default), migrate them to Unity Catalog for governed access, SQL queryability, and no storage cap.
- Legacy Unity Catalog format → current Unity Catalog format: if you configured Unity Catalog trace storage using the older schema-linked format (
catalog.schema), migrate to the current table-prefix format (catalog.schema.table_prefix) for faster time-range queries, richer attribute types, a dedicated annotations table, and support for multiple trace destinations per schema.
If you are starting fresh with no existing traces to migrate, see Store traces in Unity Catalog to configure a new experiment directly.
Migrate from experiment storage to Unity Catalog
This migration copies traces, spans, assessments, tags, and metadata from a source MLflow experiment to Unity Catalog Delta tables. The source experiment is not modified.
Note
The migration does not copy archived or deleted traces, dataset records, labeling sessions, runs, or non-trace entities.
Requirements
The prerequisites for storing traces in Unity Catalog, including the required workspace previews. See Requirements.
A Databricks SQL warehouse with
CAN USEpermission. The migration command runs on the cluster and does not use the warehouse; the warehouse is needed to view migrated traces in the UI.A Azure Databricks cluster running Databricks Runtime 15.3 or above.
The
databricks-agentsPython package:pip install "databricks-agents>=1.10.1"The following permissions:
- Read access to the source experiment.
USE_CATALOGandUSE_SCHEMAon the destination catalog and schema.CREATE TABLEon the destination schema. The migration also creates a_migration_skippedtable in the same schema if any traces are skipped.MODIFYandSELECTon the destination<prefix>_otel_*tables.SELECTis required because the migration reads existing rows to skip already-migrated traces.ALL_PRIVILEGESis not sufficient — grantMODIFYandSELECTexplicitly. See Grant permissions.
Step 1: Create a destination experiment
Create an MLflow experiment bound to a Unity Catalog trace location. The trace location is a three-part path (catalog.schema.table_prefix), and the migration writes to four Delta tables: <prefix>_otel_spans, <prefix>_otel_annotations, <prefix>_otel_logs, and <prefix>_otel_metrics.
import mlflow
from mlflow.entities.trace_location import UnityCatalog
experiment = mlflow.set_experiment(
experiment_name="/Workspace/Users/<user>/<experiment_name>",
trace_location=UnityCatalog(
catalog_name="<destination_catalog>",
schema_name="<destination_schema>",
table_prefix="<table_prefix>",
),
)
print(f"Destination experiment ID: {experiment.experiment_id}")
Save the experiment ID — you use it in Steps 2 and 3. You can ingest a few test traces to verify Unity Catalog tracing works before proceeding. See Log traces to the Unity Catalog tables.
Step 2: Switch trace logging and stop writes
Before running the migration, redirect trace logging to the new destination and stop writes to the source experiment. This ensures no traces are lost during migration.
Stop all writes to the source experiment. Verify that no notebooks, jobs, or deployed models are actively logging to it.
Replace any
set_experimentcall that points to the source experiment:import mlflow # By experiment name mlflow.set_experiment( experiment_name="/Workspace/Users/<user>/<destination_experiment_name>", ) # Or by experiment ID mlflow.set_experiment(experiment_id="<destination_experiment_id>")
Note
Trace location can also be configured through the MLFLOW_EXPERIMENT_NAME and MLFLOW_EXPERIMENT_ID environment variables, which are used by deployed agents, containerized services, model serving endpoint configurations, and IDE or local development setups. For details, see Tracing overview and Export MLflow traces to OpenTelemetry.
Step 3: Run the migration
In a Azure Databricks notebook on the cluster, run:
from databricks.migrations.migrate_traces_to_uc import run
run(
source_experiment_id="<source_experiment_id>",
target_experiment_id="<destination_experiment_id>",
)
The migration is idempotent — if interrupted (for example, due to a cluster timeout), re-run the same command. It resumes from where it left off and skips already-migrated rows.
To migrate only traces created after a specific time, pass start_time_ms (epoch milliseconds):
import time
from databricks.migrations.migrate_traces_to_uc import run
one_week_ago_ms = int((time.time() - 7 * 24 * 60 * 60) * 1000)
run(
source_experiment_id="<source_experiment_id>",
target_experiment_id="<destination_experiment_id>",
start_time_ms=one_week_ago_ms, # Only migrate traces from the last 7 days
)
After the migration completes, the source experiment is not modified and can be retained as a backup. If you use production monitoring, persist a SQL warehouse ID on the destination experiment before registering scorers. See Configure a SQL warehouse for Unity Catalog traces.
Migrate from the legacy Unity Catalog format
If you configured Unity Catalog trace storage using the older schema-linked format, your traces are stored in fixed-name tables like mlflow_experiment_trace_otel_spans and mlflow_experiment_trace_otel_logs. This migration copies spans and annotations to the current table-prefix format using Spark SQL.
How to identify if you need this migration: check whether your Unity Catalog schema contains tables named mlflow_experiment_trace_otel_spans and mlflow_experiment_trace_otel_logs. If it does, your experiment uses the older schema-linked format and is a candidate for migration.
The two formats differ as follows:
- Schema-linked (older format): the experiment's trace destination is a two-part path (
catalog.schema). Trace data lives in fixed-name tables. Tags, assessments, and metadata are stored as log events in the logs table. - Table-prefix (current format): the trace destination is a three-part path (
catalog.schema.table_prefix). Trace data lives in prefix-namespaced tables. Annotations have a dedicated table.
Requirements
Same shared prerequisites as the first migration path (UC setup, SQL warehouse, DBR 15.3+, and databricks-agents package). See the first path's requirements for the full list. Additionally:
- On the source:
USE_CATALOG,USE_SCHEMA, andSELECTon the source catalog, schema, andmlflow_experiment_trace_otel_*tables. - On the destination:
USE_CATALOG,USE_SCHEMA,MODIFY, andSELECTon the destination catalog, schema, and<table_prefix>_otel_*tables.SELECTis required because the migration reads existing rows to skip already-migrated data. CREATE TABLEon the destination schema.
Step 1: Create a destination experiment
Create an experiment linked to a Unity Catalog table-prefix location. For full setup details, see Create an experiment with a Unity Catalog trace location.
import mlflow
from mlflow.entities.trace_location import UnityCatalog
experiment = mlflow.set_experiment(
experiment_name="/Workspace/Users/<user>/<experiment_name>",
trace_location=UnityCatalog(
catalog_name="<destination_catalog>",
schema_name="<destination_schema>",
table_prefix="<table_prefix>",
),
)
print(f"Experiment ID: {experiment.experiment_id}")
Save the experiment ID. Use it to configure your notebooks, jobs, or deployed models to log traces to the new destination.
Step 2: Switch trace logging and stop writes
Update your notebooks, jobs, or deployed models to log traces to the destination experiment created in Step 1.
Important
Stop all writes to the source experiment before running the migration. Any traces written to the source tables during migration might not be copied. Verify that no notebooks, jobs, or deployed models are actively logging traces to the source experiment.
If you want to do a dry run first, you can skip this step and run the migration without switching your production workloads.
Step 3: Run the migration
In a Azure Databricks notebook on the cluster, run:
from databricks.migrations.v1_to_v2 import V1ToV2SqlMigration
migration = V1ToV2SqlMigration(
v1_source_schema="<source_catalog>.<source_schema>",
v2_destination_prefix="<destination_catalog>.<destination_schema>.<table_prefix>",
)
migration.run()
Replace the placeholders:
<source_catalog>.<source_schema>: the Unity Catalog catalog and schema where your source trace tables are stored.<destination_catalog>.<destination_schema>.<table_prefix>: the Unity Catalog catalog, schema, and table prefix for the destination. This must match the location configured in Step 1.
The migration is idempotent — if it fails partway through, re-run it. Already-migrated rows are skipped automatically.
After the migration completes, the source tables are not modified and can be retained as a backup. If you use production monitoring, persist a SQL warehouse ID on the destination experiment before registering scorers. See Configure a SQL warehouse for Unity Catalog traces.
Additional resources
- Store OpenTelemetry traces in Unity Catalog — Configure a new experiment with a Unity Catalog trace location.
- Automatic tracing and integrations — Instrument agents and route traces to Unity Catalog in production.
- Set up production monitoring — Run scorers against traces stored in Unity Catalog.