How to Manage Model Versioning and Registries in MLOps

Model versioning and registries provide immutable artifact storage with full metadata lineage, enabling reproducible experiments and safe promotion from staging to production.

The harvard-edge/cs249r_book repository defines model versioning and registries as core MLOps components that bridge the gap between experimental training and production deployment. By treating every trained model as an immutable artifact with captured hyperparameters, evaluation metrics, and environment specifications, teams can manage model versioning and registries to ensure reproducibility and auditability across the entire machine learning lifecycle.

What Is Model Versioning?

Model versioning is the practice of registering each trained model as an immutable artifact with comprehensive metadata. According to the source code analysis in book/quarto/contents/core/ops/ops.qmd around line 576, this process captures hyperparameters, evaluation metrics, environment specifications, and a unique version identifier.

When you manage model versioning and registries correctly, you create an auditable trail that links a specific model artifact to the exact code, data, and configuration that produced it. This guarantees you can roll back to a known-good model and determine which dataset version and feature store snapshot were used during training.

Immutable Artifacts and Metadata

Every model version must be immutable once registered. The registry stores the model binary alongside a metadata JSON file that includes:

  • Framework version (e.g., tinytorch commit hash)
  • Hyperparameters (learning rate, batch size, architecture)
  • Performance metrics (training accuracy, validation loss)
  • Data lineage (dataset version, feature store snapshot ID)
  • Environment specs (CUDA version, Python version, dependencies)

Understanding Model Registries

A model registry is a centralized store that lists all model versions and exposes operations for promote, deploy, and deprecate. As documented in book/quarto/contents/core/ops/ops.qmd at line 576, the registry provides a single source of truth for the serving layer and makes lineage visualization possible.

The registry decouples training from deployment. Data scientists can push new versions to the registry without affecting production systems, while DevOps engineers can promote specific versions through staging environments based on automated tests or manual approval gates.

Registry Operations

The standard lifecycle operations in a model registry include:

  • Register: Upload a new model artifact with metadata after training completes
  • List: Query all available versions with filtering by stage (development, staging, production)
  • Promote: Move a version from one stage to another (e.g., staging to production)
  • Deprecate: Mark a version as outdated or unsafe for serving without deleting the artifact
  • Rollback: Switch the production endpoint to point to a previous version

TinyTorch Command Registry Pattern

The cs249r_book repository demonstrates a pluggable command registry pattern in tinytorch/tito/main.py (lines 84-95) that you can reuse for model registry CLI commands. The BaseCommand class allows automatic discovery of subcommands, making it easy to add registry operations like tinytorch model-registry list or tinytorch model-registry promote.

Implementing Model Versioning in Practice

Below is a minimal implementation following the patterns described in the repository. This example creates a local model registry with immutable artifacts and JSON metadata.


# utils/model_registry.py

import json
from pathlib import Path
from datetime import datetime
import uuid

REGISTRY_ROOT = Path(__file__).parent / "registry"
REGISTRY_ROOT.mkdir(exist_ok=True)

def _version_id() -> str:
    """Generate a short, timestamped version string."""
    return f"v{datetime.utcnow().strftime('%Y%m%d%H%M%S')}-{uuid.uuid4().hex[:6]}"

def register_model(model_path: Path, metadata: dict) -> str:
    """Persist a model file and its metadata in the registry."""
    version = _version_id()
    version_dir = REGISTRY_ROOT / version
    version_dir.mkdir()
    # copy model artifact

    target = version_dir / model_path.name
    target.write_bytes(model_path.read_bytes())
    # enrich metadata

    metadata.update({
        "version": version,
        "registered_at": datetime.utcnow().isoformat(),
        "model_file": target.name,
    })
    (version_dir / "metadata.json").write_text(json.dumps(metadata, indent=2))
    return version

def list_versions() -> list[str]:
    """Return all registered version identifiers."""
    return sorted([p.name for p in REGISTRY_ROOT.iterdir() if p.is_dir()], reverse=True)

def get_metadata(version: str) -> dict:
    """Load metadata for a given version."""
    meta_path = REGISTRY_ROOT / version / "metadata.json"
    return json.loads(meta_path.read_text())

Registering a Model After Training

Integrate the registry into your training loop to automatically capture every experiment:

from pathlib import Path
from utils.model_registry import register_model

# after training...

model_file = Path("outputs/my_model.pt")
meta = {
    "framework": "tinytorch",
    "hyperparameters": {"lr": 0.01, "epochs": 20},
    "train_accuracy": 0.93,
    "validation_accuracy": 0.88,
}
version = register_model(model_file, meta)
print(f"Model registered as {version}")

Listing and Retrieving Versions

Query the registry to inspect available models and their performance metrics:

from utils.model_registry import list_versions, get_metadata

for v in list_versions()[:5]:  # show latest 5

    meta = get_metadata(v)
    print(f"{v}: {meta['validation_accuracy']*100:.1f}% val acc")

Integrating with CI/CD Pipelines

Model versioning and registries must connect to your broader MLOps pipeline. According to book/quarto/contents/core/workflow/workflow.qmd at line 529, versioning ties model artifacts to data versioning, feature stores, and CI/CD automation.

When a pipeline (Airflow, Prefect, or GitHub Actions) reads from the model registry, it pulls the exact data version (via DVC or external storage) and the feature store snapshot referenced in the model metadata. This guarantees that a model can be rebuilt exactly, satisfying reproducibility requirements for regulated industries.

Promotion gates in the registry trigger deployment workflows. When a model version moves from staging to production, the CI pipeline updates the serving endpoint configuration to point to the new artifact path, while the registry logs the promotion event for audit purposes.

Summary

  • Model versioning creates immutable artifacts with complete metadata (hyperparameters, metrics, environment specs) to ensure reproducibility and auditability.
  • Model registries provide centralized storage with lifecycle operations (register, promote, deprecate) that decouple training from production deployment.
  • The cs249r_book repository defines these concepts in book/quarto/contents/core/ops/ops.qmd and demonstrates implementation patterns using the TinyTorch command registry in tinytorch/tito/main.py.
  • Production implementations should integrate registries with data versioning (DVC), feature stores, and CI/CD pipelines to maintain end-to-end lineage from raw data to serving endpoint.

Frequently Asked Questions

What is the difference between model versioning and a model registry?

Model versioning is the practice of capturing a trained model as an immutable artifact with metadata, while a model registry is the centralized system that stores these versions and manages their lifecycle stages. Versioning ensures you can reproduce a specific model state; the registry provides the interface to promote, deploy, or deprecate those versions across environments.

How does model versioning ensure reproducibility in MLOps?

By storing immutable artifacts alongside metadata that includes the exact hyperparameters, training dataset version, feature store snapshot, and environment specifications (CUDA, Python, library versions), model versioning creates a complete provenance record. As documented in book/quarto/contents/core/workflow/workflow.qmd, this allows pipelines to rebuild the model exactly or roll back to previous versions when production issues arise.

Can I implement a model registry without using commercial tools like MLflow?

Yes. The cs249r_book repository demonstrates that you can build a functional registry using simple filesystem storage and JSON metadata, as shown in the utils/model_registry.py example. For CLI integration, you can reuse the TinyTorch command registry pattern from tinytorch/tito/main.py to create subcommands for register, list, and promote operations without external dependencies.

What role does the model registry play in CI/CD pipelines?

The model registry acts as the single source of truth that decouples model training from deployment. CI/CD pipelines query the registry to determine which model version to deploy, trigger promotion workflows when validation criteria are met, and maintain lineage links between the model artifact, data version, and serving endpoint configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →