Git LFS and DVC: The Ultimate Guide to Managing Large Artifacts in MLOps

The Growing Challenge of Large Files in ML Projects

Machine learning practitioners face a unique challenge that traditional software developers rarely encounter: managing extremely large files within version control systems. While a typical software repository might consist of code files measuring in kilobytes, ML projects routinely incorporate:

  • Datasets ranging from hundreds of megabytes to many gigabytes
  • Trained model weights often exceeding 1GB (especially for deep learning models)
  • Feature stores and preprocessed data artifacts
  • Evaluation results including visualizations and benchmark outputs

This creates a fundamental tension. On one side, these artifacts are essential components that need version control just as much as code does. On the other side, Git — the de facto standard for version control — was designed for tracking text files, not multi-gigabyte binaries.

The Git Limitation Reality

Git’s architecture creates several specific problems when dealing with large files:

Repository Bloat: Git stores the complete history of every file. When you commit a 500MB dataset and then update it five times, your repository now contains 3GB of data just for that file’s history.Performance Degradation: Git operations slow to a crawl with large binaries. A simplegit clone

that normally takes seconds can take hours when large files are involved.Collaboration Friction: Team members must download the entire repository history, including all versions of all large files, creating significant bandwidth consumption and waiting times.Platform Limitations: GitHub, GitLab, and similar platforms impose size limits — GitHub, for instance, warns on files larger than 50MB and blocks files exceeding 100MB.CI/CD Pipeline Inefficiency: Continuous integration environments must repeatedly download large files, increasing build times and cloud compute costs.

This creates a practical dilemma for ML teams: they need the versioning capabilities of Git but cannot use standard Git workflows for their largest and most important artifacts.

The Integration vs. Separation Dilemma

When facing these limitations, ML teams typically consider two general approaches:

The Integration Approach

Many teams prefer keeping everything together in one repository, following GitOps principles. The advantages are clear:

Atomic Changes: Code and data modifications can be committed together, ensuring that model code always works with the corresponding data versionSimplified Workflows: Developers can use familiar Git commands and don’t need to learn additional toolsConsistent History: A single timeline of project evolution covering both code and dataEasier Reproducibility: Checking out a specific commit gets you the exact state of both code and data

This approach is especially appealing to teams transitioning from software development to ML, as it maintains familiar workflows.

The Separation Approach

The alternative is separating large files from the Git repository entirely:

Storing datasets in object storage(S3, GCS, Azure Blob)Using database systemsfor feature storesImplementing artifact registriesfor model weightsCreating custom metadata systemsto maintain relationships

While this approach solves the Git limitations problem, it introduces new challenges:

Version Synchronization: How do you ensure that code commit A works with dataset version B?Cognitive Overhead: Developers must remember which files are where and learn multiple toolsComplex Reproducibility: Recreating a specific project state requires careful coordination across systemsIncreased Infrastructure: More systems to maintain, secure, and pay for

The Middle Ground: Git Extensions

Recognizing this dilemma, several tools have emerged that offer a middle ground — extending Git’s capabilities to handle large files while preserving much of its workflow. The two most prominent are Git LFS and DVC.

These solutions aim to provide:

  • The familiar Git interface for all operations
  • Efficient storage and transfer of large files
  • Integration with cloud storage providers
  • Specialized features for machine learning workflows

In the sections that follow, we’ll dive deep into both Git LFS and DVC, exploring how they work and when to use each one. We’ll examine their architectures, provide practical setup guides, and compare them across real-world ML scenarios.

By the end, you’ll have a clear understanding of how to implement an effective strategy for managing your ML project’s largest artifacts, enabling smooth collaboration without sacrificing version control.

Git LFS: GitHub’s Native Solution for Large Files

Git Large File Storage (LFS) emerged in 2015 as GitHub’s answer to the large file dilemma. Developed originally by GitHub but now an open-source project, Git LFS has become deeply integrated into the GitHub ecosystem and many other Git platforms.

How Git LFS Works: The Technical Architecture

Git LFS employs a clever “pointer” system that maintains Git’s workflow while offloading large file storage:

Pointer Files: Instead of storing large files directly in the Git repository, Git LFS replaces them with tiny text files (typically less than 1KB) called “pointer files.” These files contain:

  • The OID (Object ID): A SHA-256 hash that uniquely identifies the file’s content
  • The file size
  • A reference to where the actual file is stored

Content-Addressable Storage: The actual file content is stored in a separate LFS server, indexed by its content hash. This means:

  • Identical files are stored only once (deduplication)
  • Files can be verified for integrity
  • Content is immutable and referenced by its hash

Transparent Operations: Git LFS integrates with standard Git commands, automatically:

  • Replacing large files with pointers during git add

  • Uploading file content to LFS storage during git push

  • Downloading content and replacing pointers with actual files during git checkout

This architecture means that Git itself only tracks and transfers the small pointer files, while a separate LFS client handles the large file transfers behind the scenes.

Setting Up Git LFS: A Practical Guide

Setting up Git LFS requires a few straightforward steps:

1. Installation

Ubuntu/Debian

sudo apt-get install git-lfs# Windows (using Chocolatey)

choco install git-lfs# macOS (using Homebrew)

brew install git-lfs# Or download from https://git-lfs.github.com/

2. System-Wide Initialization

This sets up the Git LFS hooks in your global Git configuration.

git lfs install

3. Repository Configuration

# Navigate to your repository

cd my-ml-project

Start tracking specific file patterns

git lfs track “*.h5” # Keras models

git lfs track “*.pkl” # Pickled Python objects

git lfs track “*.parquet” # Parquet files

git lfs track “*.csv” # CSV datasets

git lfs track “*.zip” # Compressed archives

git lfs track “data/**” # Everything in the data directory

IMPORTANT: Commit the .gitattributes file where tracking config is stored

git add .gitattributes

git commit -m “Configure Git LFS tracking patterns”

4. Using Git LFS

Once configured, you can use Git normally. Git LFS intercepts operations involving tracked file patterns:

# Adding a large file works like normal Git

git add models/my_large_model.h5

git commit -m “Add trained model”

git push

Pulling works transparently too

git pull

Clone with LFS content

git clone https://github.com/username/repo.git

5. Managing LFS Objects

Git LFS provides commands for managing the large files:

# List all tracked files

git lfs ls-files

See tracking patterns

git lfs track

Pull all LFS objects (not just the ones needed for current checkout)

git lfs pull —all

Pre-download LFS objects for a specific branch without checking it out

git lfs fetch —recent

Clean up local LFS cache (remove files not referenced by commits)

git lfs prune

LFS Storage Options

Git LFS content can be stored in several places:

1. GitHub’s LFS Storage

GitHub provides LFS storage by default, but with limitations:

  • Free plans include 1GB of LFS storage and 1GB monthly bandwidth
  • Exceeding these limits incurs additional costs ($5 per month per 50GB of storage)

2. Self-Hosted LFS Server

For complete control, you can host your own LFS server:

  • Git LFS Server (reference implementation)
  • MinIO (compatible with S3 API)

3. Third-Party LFS Services

Several services offer Git LFS hosting:

  • GitLab
  • Azure DevOps
  • Bitbucket

Strengths of Git LFS

For ML teams, Git LFS offers several key advantages:

Familiar Git Workflow: Team members use standard Git commands; the LFS operations happen transparently.Platform Integration: Deep integration with GitHub, GitLab, and other platforms, including web interfaces.Selective Checkout: LFS objects are only downloaded when checking out a branch that needs them, saving bandwidth and storage.Simple Setup: Adding LFS to existing repositories is straightforward.Language and Framework Agnostic: Works with any ML framework or file format.CI/CD Integration: Most CI platforms (GitHub Actions, GitLab CI, Jenkins) have built-in support for Git LFS.

Limitations for ML Workflows

However, Git LFS has limitations when applied to ML workflows:

No Pipeline Awareness: LFS doesn’t understand relationships between files (e.g., which dataset produced which model).Limited Metadata: LFS doesn’t track ML-specific metadata like training metrics or experiment parameters.Storage Costs: GitHub and similar platforms charge for LFS storage beyond free tier limits.Performance with Very Large Files: While better than plain Git, LFS can still struggle with extremely large files (10GB+).No Dataset Versioning Features: For dataset-specific operations like splits and transformations, LFS offers no specialized tools.

In the next section, we’ll explore DVC (Data Version Control), which addresses many of these ML-specific limitations while still leveraging Git’s underlying architecture.

DVC: The ML-Native Approach to Version Control

Data Version Control (DVC) emerged from the ML community’s specific needs, designed from the ground up to address the unique challenges of machine learning workflows. While Git LFS extends Git to handle large files, DVC reimagines version control for the entire ML lifecycle.

The DVC Philosophy: Beyond File Storage

DVC’s approach is fundamentally different from Git LFS, focusing on:

Data and Model Versioning: Not just storing large files, but tracking their lineage and relationshipsPipeline Management: Capturing the entire workflow from data preprocessing to model evaluationExperiment Tracking: Monitoring and comparing metrics across different model iterationsReproducibility: Ensuring any experiment can be precisely recreated

This comprehensive approach makes DVC more than just a large file storage solution — it’s a framework for managing the entire ML development process.

How DVC Works: Technical Architecture

DVC operates alongside Git, creating a powerful hybrid version control system:

Metadata in Git: DVC stores lightweight metadata files in your Git repositoryData in Remote Storage: The actual large files live in configurable remote storage (S3, GCS, Azure, etc.)Local Cache: DVC maintains a local content-addressed cache for efficient operations

When you add a file to DVC:

dvc add data/large_dataset.csv

DVC performs these operations:

  • Calculates a hash of the file content
  • Moves the file to the local cache, named by its hash
  • Creates a small metadata file ( data/large_dataset.csv.dvc

) containing the hash - Adds the original file to .gitignore

to prevent Git from tracking it - You then commit the .dvc

file to Git

This pattern achieves several important goals:

  • Git only tracks small metadata files
  • Large files can be stored anywhere
  • File integrity is guaranteed by content hashing
  • The repository remains lightweight and fast

Setting Up DVC: A Practical Guide

1. Installation

# Using pip (recommended)

pip install dvc

For specific remote storage support

pip install dvc[s3] # For Amazon S3

pip install dvc[azure] # For Azure Blob Storage

pip install dvc[gs] # For Google Cloud Storage

pip install dvc[all] # All remote storage options

Alternative: Using conda

conda install -c conda-forge dvc

2. Repository Initialization

# Navigate to your Git repository

cd my-ml-project

Initialize DVC

dvc init

Commit DVC configuration files

git add .dvc .dvcignore

git commit -m “Initialize DVC”

3. Setting Up Remote Storage

# Add a remote storage location

dvc remote add -d myremote s3://my-bucket/dvc-storage

Or for other storage backends:

dvc remote add -d myremote gs://my-bucket/dvc-storage

dvc remote add -d myremote azure://my-container/dvc-storage

dvc remote add -d myremote /path/to/local/storage # Local directory

Commit the configuration

git add .dvc/config

git commit -m “Configure DVC remote storage”

4. Adding and Versioning Data

# Add a large file or directory to DVC

dvc add data/training_data.parquet

dvc add models/

Commit the metadata file

git add data/training_data.parquet.dvc models.dvc

git commit -m “Add training data and models”

Push the actual data to remote storage

dvc push

5. Retrieving Data

# Clone the repository (gets only code and .dvc files)

git clone https://github.com/username/repo.git

cd repo

Pull all DVC-tracked files

dvc pull

Or pull only specific files

dvc pull data/training_data.parquet

Beyond Storage: DVC’s Advanced Features

What truly sets DVC apart from Git LFS is its ML-specific features:

1. Data Pipelines

DVC allows you to define reproducible pipelines that connect data, code, and models:

# Define a pipeline stage

dvc run -n preprocess \

-d src/preprocess.py -d data/raw_data.csv \

-o data/features.parquet \

python src/preprocess.py data/raw_data.csv data/features.parquet

Define another stage that depends on the previous one

dvc run -n train \

-d src/train.py -d data/features.parquet \

-o models/model.pkl -M metrics.json \

python src/train.py data/features.parquet models/model.pkl

These commands create a dvc.yaml

file that defines your pipeline. Running dvc repro

will:

  • Check which files have changed
  • Re-run only the affected pipeline stages
  • Update outputs and metrics

This ensures reproducibility and saves computation by only running what’s necessary.

2. Experiment Tracking

DVC tracks metrics across experiments:

# Train with different parameters

dvc exp run —set-param train.learning_rate=0.1

dvc exp run —set-param train.learning_rate=0.01

Compare experiments

dvc exp show

Apply a successful experiment

dvc exp apply exp-a123b

This provides a lightweight alternative to dedicated experiment tracking tools, all integrated with your version control system.

3. Metrics and Plots

DVC can track and visualize metrics across experiments:

# Define metrics output in your pipeline

dvc run -n evaluate \

-d src/evaluate.py -d models/model.pkl -d data/test.csv \

-M metrics.json -O plots/confusion_matrix.csv \

python src/evaluate.py

View metrics

dvc metrics show

Compare metrics across Git tags/branches

dvc metrics diff main v1.0

Generate plots

dvc plots show plots/confusion_matrix.csv

Strengths of DVC for ML Workflows

DVC offers several advantages for ML teams:

Complete ML Lifecycle: Manages data, code, models, and metrics in one systemStorage Flexibility: Works with any cloud storage provider or even local directoriesPipeline Management: Captures dependencies between artifacts for reproducibilityExperiment Tracking: Lightweight tracking of hyperparameters and metricsTeam Collaboration: Enables sharing of data and models through standard Git workflowsOpen Source: Completely free and open source with an active community

Limitations and Considerations

However, DVC does have some trade-offs:

Learning Curve: More complex than Git LFS, requiring understanding of new conceptsAdditional Tooling: Requires installing Python and DVC on all development machinesLess Platform Integration: Less integrated with GitHub/GitLab interfaces than Git LFSSeparate Commands: Requires using both Git and DVC commands in workflowsStill Emerging: While stable, the ecosystem is still evolving compared to Git

In the next section, we’ll compare Git LFS and DVC across practical ML scenarios to help you choose the right approach for your projects.

Practical Comparison: Git LFS vs. DVC in Real-World Scenarios

While understanding the theoretical differences between Git LFS and DVC is valuable, seeing how they perform in realistic ML workflows provides more actionable insights. Let’s examine three common scenarios that ML teams face and compare how each tool addresses them.

Scenario 1: Versioning a 10GB Dataset

Imagine your team works with a 10GB training dataset that undergoes periodic updates and refinements. How would each tool handle this?

With Git LFS:

# Track the dataset format

git lfs track “*.parquet”

git add .gitattributes

git commit -m “Configure LFS tracking for parquet files”

Add the dataset

git add training_data.parquet

git commit -m “Add training dataset v1”

git push

Later, update the dataset

(modify training_data.parquet)

git add training_data.parquet

git commit -m “Update dataset with new samples”

git push

A team member would get the latest version

git pull

The latest version is automatically downloaded

What’s happening behind the scenes:

  • Git LFS stores each version of the dataset (10GB per version)
  • The Git repository contains only small pointer files
  • When pulling, Git LFS downloads only the version you need
  • No explicit relationship with code or models is recorded

With DVC:

# Add the dataset to DVC

dvc add training_data.parquet

git add training_data.parquet.dvc .gitignore

git commit -m “Add training dataset v1”

git push

dvc push

Later, update the dataset

(modify training_data.parquet)

dvc add training_data.parquet # Re-add after changes

git add training_data.parquet.dvc

git commit -m “Update dataset with new samples”

git push

dvc push

A team member would get the latest version

git pull

dvc pull

What’s happening behind the scenes:

  • DVC stores each version in remote storage (10GB per version)
  • Git tracks the small .dvc metadata files
  • DVC manages the relationship between Git commits and dataset versions
  • Team members need to run both git pull

anddvc pull

Key differences in this scenario:

Command Complexity: Git LFS requires fewer commands but DVC provides more explicit controlStorage: Both store each version of the datasetVersioning Granularity: DVC offers more tools for comparing dataset versionsIntegration with Code: DVC can formally link dataset versions to code versions

Scenario 2: Managing an ML Pipeline with Changing Inputs

Now let’s consider a more complex scenario: an ML pipeline that processes raw data, generates features, trains models, and evaluates performance. How do the tools handle this workflow?

With Git LFS:

# Track all large files

git lfs track “data//*.csv” “data//.parquet” “models/.pkl”

git add .gitattributes

git commit -m “Set up LFS tracking patterns”

To run the pipeline, you’d use scripts or a workflow tool

python scripts/process_data.py # Generates features.parquet

python scripts/train_model.py # Generates model.pkl

python scripts/evaluate.py # Generates metrics.json

Commit all outputs

git add data/features.parquet models/model.pkl metrics.json

git commit -m “Run pipeline with latest data”

git push

What’s happening behind the scenes:

  • Git LFS tracks large files but has no awareness of the pipeline structure
  • Dependencies between inputs and outputs are not formally tracked
  • You need external tools or documentation to remember pipeline steps
  • If someone changes an input, they need to remember to re-run the affected pipeline steps

With DVC:

# Define the pipeline stages

dvc stage add -n process \

-d scripts/process_data.py -d data/raw_data.csv \

-o data/features.parquet \

python scripts/process_data.py

dvc stage add -n train \

-d scripts/train_model.py -d data/features.parquet \

-o models/model.pkl \

python scripts/train_model.py

dvc stage add -n evaluate \

-d scripts/evaluate.py -d models/model.pkl -d data/test.csv \

-o metrics.json \

python scripts/evaluate.py

Run the entire pipeline

dvc repro

Commit the pipeline definition and outputs

git add dvc.yaml dvc.lock data/features.parquet.dvc models/model.pkl.dvc metrics.json

git commit -m “Run pipeline with latest data”

git push

dvc push

What’s happening behind the scenes:

  • DVC formally tracks the pipeline structure in dvc.yaml

  • Dependencies between inputs and outputs are explicitly defined

  • DVC knows which stages to re-run when inputs change

  • The pipeline becomes a versioned artifact itself

Key differences in this scenario:

Dependency Tracking: DVC has native understanding of which files depend on othersSelective Execution: DVC can run only the parts of the pipeline affected by changesReproducibility: DVC pipelines are self-documenting and ensure consistent resultsComplexity: DVC requires more setup but provides more automation

Conclusion: Choosing the Right Tool for Your ML Workflows

When deciding between Git LFS and DVC for managing large artifacts in your machine learning projects, there’s no one-size-fits-all answer. Your choice should be guided by your team’s specific needs, technical context, and workflow complexity.

When to Choose Git LFS

Git LFS is likely the better choice when:

You need a simple solutionwith minimal learning curveYour team is primarily software engineersfamiliar with GitYou want tight integrationwith GitHub or GitLab platformsYour large files are relatively staticand don’t change frequentlyYour ML workflows are straightforwardwithout complex pipeline dependenciesCI/CD integrationis a primary concern

When to Choose DVC

DVC becomes the preferable option when:

You have complex ML pipelineswith multiple interdependent stagesYour team needs experiment trackingintegrated with version controlYou want flexible storage backendsbeyond what Git hosting providesReproducibilityis a critical requirementYour datasets are very large(10GB+) or change frequentlyYou need specialized ML featureslike metrics tracking and pipeline visualization

Hybrid Approaches

Many teams find success with hybrid approaches:

Using Both Tools Together: Git LFS for certain assets (documentation images, small datasets) and DVC for ML-specific artifacts (large datasets, models)Starting with Git LFS, Growing into DVC: Beginning with the simpler tool and gradually adopting DVC as workflows matureDVC for Data, Other Tools for Experiments: Using DVC for data and pipeline management while employing specialized tools like MLflow or Weights & Biases for experiment tracking

Final Recommendations

Regardless of which tool you choose, follow these best practices:

Commit to a Consistent Workflow: Once you choose a tool, establish clear team guidelinesDocument Your Approach: Create clear documentation for team members on how to use the chosen toolsRegularly Review Storage Usage: Monitor storage consumption to avoid unexpected costsConsider Pruning Historical Data: Not every version of every artifact needs to be kept foreverAutomate Where Possible: Use CI/CD to enforce consistent practices

The management of large artifacts in ML projects remains an evolving challenge, but both Git LFS and DVC offer viable solutions that significantly improve upon raw Git. By understanding their strengths and limitations, you can make an informed choice that supports rather than hinders your team’s productivity.

Remember that the ultimate goal is not perfect version control, but enabling your team to collaborate effectively, iterate rapidly, and produce reproducible, high-quality machine learning models. Choose the tool that best supports those fundamental objectives for your specific context.