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 →

DVC metrics and plots

dvc metrics is a pair of commands that read the metrics files a pipeline declares and print them, either as a table of the current numbers or as the change since the last commit.

Last updated: 19 Oct, 2026 · MLOps

The reruns in dvc repro and the cache each ended with a line of metrics scrolling past in the log. Reading a result off a log is fine once. What a project needs is the numbers for the commit you are on, and the difference between them and the numbers of the commit before.

Declaring a metrics file

The train stage already names one. cache: false is the part that matters here: DVC leaves the file alone instead of moving it into the cache, so git tracks it and every commit carries the numbers that commit's model scored.

yaml
    metrics:
      - artifacts/model_trainer/metrics.json:
          cache: false

The file is the plain JSON the trainer writes, a flat map of name to number, which is the shape DVC reads.

json
{
    "r2": 0.8485,
    "mae": 4.6996,
    "rmse": 6.0721
}

Printing the current numbers

bash
dvc metrics show
Captured from a real run
Path                                  mae     r2      rmse
artifacts/model_trainer/metrics.json  4.6996  0.8485  6.0721

One row per metrics file, one column per metric, in alphabetical order rather than the order the file lists them. With several stages reporting, each file gets its own row, which is the quickest view of a pipeline's results.

Comparing with the last commit

dvc metrics diff compares what is in the working folder with the latest committed version, which gives it one requirement, and meeting that requirement is the point of cache: false. Where the metrics file has never been committed, there is nothing to compare against:

bash
dvc metrics diff
Captured from a real run
DVC failed to load some metrics for following revisions: 'HEAD'.
Path                                  Metric    HEAD    workspace    Change
artifacts/model_trainer/metrics.json  mae       -       4.8467       -
artifacts/model_trainer/metrics.json  r2        -       0.8374       -
artifacts/model_trainer/metrics.json  rmse      -       6.2904       -

The HEAD column is empty and the change is a dash, because the file is not in that commit. Commit artifacts/model_trainer/metrics.json alongside the code and dvc.lock, and the same command, after the depth change of the previous lesson, has both sides to work with:

bash
dvc metrics diff
Captured from a real run
Path                                  Metric    HEAD    workspace    Change
artifacts/model_trainer/metrics.json  mae       4.6996  4.8467       0.1471
artifacts/model_trainer/metrics.json  r2        0.8485  0.8374       -0.0111
artifacts/model_trainer/metrics.json  rmse      6.0721  6.2904       0.2183
  • HEAD is the committed run, at depth 12, and workspace is the one in front of you, at depth 4.
  • Change is workspace minus HEAD. MAE rose by 0.1471 and RMSE by 0.2183, while r2 fell by 0.0111.
  • Read the sign, not the size. An increase in MAE or RMSE is worse, an increase in r2 is better, and DVC has no idea which of your metrics are which.
  • Only changed metrics are listed unless you pass --all.

Seeing which parameter moved

A metric that moved is half the story. The matching command over the parameter files says what you changed to cause it.

bash
dvc params diff
Captured from a real run
Path         Param      HEAD    workspace
params.yaml  MAX_DEPTH  12      4

The two commands together are a record of one experiment: this parameter went from 12 to 4, and these three numbers moved this much.

Plotting a series with dvc plots

A metric is one number per run. A plot is a series inside one run: a loss curve over epochs, a prediction against its true value. DVC reads those from a CSV or JSON file that a stage writes, named under a plots key with the columns to put on each axis.

yaml
plots:
  - logs.csv:
      x: epoch
      y: accuracy
bash
dvc plots show
Captured from a real run
file:///Users/usr/src/dvc_plots/index.html
  • The command writes a page, not a picture. It renders the series into dvc_plots/index.html and prints the path for you to open.
  • dvc plots diff is the counterpart of dvc metrics diff: it draws the same series from two commits on one set of axes.
  • The student-performance pipeline has no series to draw, since one fit produces one set of numbers rather than a curve. The command and the definition above come from the DVC plots documentation linked below, and nothing on this page was run against them.

Metrics vs plots

metricsplots
HoldsOne number per nameA series of rows
FileA flat JSON or YAML mapA CSV or JSON of records
Shown bydvc metrics show, dvc metrics diffdvc plots show, dvc plots diff
OutputA table in the terminalAn HTML page you open
Good forComparing runs at a glanceWatching something move within a run

Where the metric commands fit

  • Before a pull request. Run the diff and paste it in: the review then shows the code change and what it did to the score.
  • In a retraining job. The job can read the diff and refuse to promote a model whose r2 fell.
  • Through a tuning session. Edit a parameter, rerun the pipeline, read the diff, and repeat without touching a spreadsheet.
Watch out. Caching a metrics file is the mistake that quietly breaks all of this. Drop cache: false, or let a .gitignore rule cover the artifacts folder, and the file never reaches a commit, so every diff prints the empty HEAD column above. The numbers are small text and belong in git.
Try it yourself
  • Run dvc metrics diff --all to see the metrics that did not move listed too.
  • Commit the depth-4 run, change MAX_DEPTH to 8, rerun the pipeline and read the new diff against it.
  • Pass an older commit to the command, as dvc metrics diff HEAD~1, to compare with a run further back.

Slow is fine. Stopping is the only problem.