Experiments in DVC allow you to run multiple variations of your pipeline with different parameters, code changes, or data, while automatically tracking all results. Each experiment is a Git commit that DVC manages separately, keeping your main branch clean while preserving full reproducibility.
Key Concept: Experiments are Git commits in a special namespace (refs/exps/) that don’t clutter your branch history. They capture code, parameters, metrics, and outputs for each run.
The core experiments manager is defined in dvc/repo/experiments/__init__.py:43-58:
class Experiments: """Class that manages experiments in a DVC repo. Args: repo (dvc.repo.Repo): repo instance that these experiments belong to. """ BRANCH_RE = re.compile(r"^(?P<baseline_rev>[a-f0-9]{7})-(?P<exp_sha>[a-f0-9]+)") def __init__(self, repo): from dvc.scm import NoSCMError if repo.config["core"].get("no_scm", False): raise NoSCMError self.repo = repo
# Remove specific experimentdvc exp remove exp-a1b2c# Remove all experimentsdvc exp remove --all# Remove experiments from specific baselinedvc exp remove --rev main
From dvc/repo/experiments/remove.py, the implementation handles cleanup of Git refs and associated data.
For long-running training, save intermediate results:
# In your training scriptfrom dvclive import Livewith Live() as live: for epoch in range(100): # Training code... live.log_metric("loss", loss) live.next_step() # Creates checkpoint
Each checkpoint becomes a separate experiment you can compare and apply.
Run experiments across parameter ranges using Hydra:
dvc exp run --queue -S 'learning_rate=0.001,0.01,0.1'dvc exp run --queue -S 'learning_rate=range(0.001,0.1,0.01)'
From dvc/repo/experiments/run.py:58-95:
hydra_sweep = any( x.is_sweep_override() for param_file in path_overrides for x in to_hydra_overrides(path_overrides[param_file]))if hydra_sweep and not queue: raise InvalidArgumentError( "Sweep overrides can't be used without `--queue`" )
This queues multiple experiments, one for each parameter combination.
# Show specific metricsdvc exp show --include-metrics loss,accuracy# Show specific paramsdvc exp show --include-params train.lr,train.epochs# Sort by metricdvc exp show --sort-by loss# Show only running or queued experimentsdvc exp show --queued
Each experiment is associated with a baseline commit. From dvc/repo/experiments/__init__.py:256-289:
def check_baseline(self, exp_rev): baseline_sha = self.repo.scm.get_rev() if exp_rev == baseline_sha: return exp_rev exp_baseline = self._get_baseline(exp_rev) if exp_baseline is None: # if we can't tell from branch name, fall back to parent commit exp_commit = self.scm.resolve_commit(exp_rev) if exp_commit: exp_baseline = first(exp_commit.parents) if exp_baseline == baseline_sha: return exp_baseline raise BaselineMismatchError(exp_baseline, baseline_sha)
This ensures experiments are only applied to compatible commits, preventing confusion.
DVC creates a temporary directory, runs the experiment there, and cleans up afterward. Your workspace remains unchanged.From dvc/repo/experiments/__init__.py:114-132:
def reproduce_one( self, tmp_dir: bool = False, copy_paths: Optional[list[str]] = None, message: Optional[str] = None, **kwargs,): """Reproduce and checkout a single (standalone) experiment.""" exp_queue: BaseStashQueue = ( self.tempdir_queue if tmp_dir else self.workspace_queue )