The Problem We're All Facing
Your repository started lean. Now it's bloated. Design files, video clips, database dumps, and compiled binaries have crept in, and cloning takes minutes instead of seconds. This is where Git LFS: a practical guide with real production examples becomes essential for teams handling large files at scale. Whether you're managing design assets in a fintech platform, video thumbnails in a ride-hailing app, or ML training datasets in a SaaS pipeline, Git LFS solves the exact problem of storing large files without bloating your repository.
Stores Large Files Outside Git Objects
Git LFS (Large File Storage) doesn't store the actual file content in your repository. Instead, it stores a small text pointer file—typically a few hundred bytes—while the real binary lives on a remote LFS server. When you clone or pull, Git swaps the pointer for the actual file transparently.
Here's what happens under the hood: normally, a 500 MB video file gets added to Git's object database. Every developer clones the full history, meaning even if you delete the file later, it stays in .git/objects. With LFS, Git stores only a pointer like this:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2e07b47dfdc2a3f6b9c5e92d8e9c3a1b5f6d9e8c7b6a5f4e3d2c
size 512000000The actual 512 MB file lives on your LFS server—GitHub, GitLab, Gitea, or a custom S3 backend. This keeps your Git repository lean (measured in MB, not GB) while preserving your full versioning history.
In practice, we've seen teams move from 8 GB repositories to 200 MB by migrating design files and media. Clone time dropped from 3 minutes to 12 seconds on standard connections.
Track Patterns Like *.psd
Git LFS works through a .gitattributes file in your repository root. Instead of manually deciding which files use LFS for each commit, you define patterns once, and Git applies LFS automatically.
Create or edit .gitattributes in your repository root:
# Design files
*.psd filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
*.figma filter=lfs diff=lfs merge=lfs -text
# Video and audio
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.m4a filter=lfs diff=lfs merge=lfs -text
# Images (high resolution)
*.psd filter=lfs diff=lfs merge=lfs -text
*.psb filter=lfs diff=lfs merge=lfs -text
# Archives and databases
*.zip filter=lfs diff=lfs merge=lfs -text
*.sql filter=lfs diff=lfs merge=lfs -text
*.dump filter=lfs diff=lfs merge=lfs -text
# Machine learning models
*.pkl filter=lfs diff=lfs merge=lfs -text
*.h5 filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
# Node modules and dependencies (if absolutely necessary)
node_modules/ filter=lfs diff=lfs merge=lfs -textCommit this file to your repository. From that point forward, any .psd file you stage will automatically use LFS:
git add marketing/hero-banner.psd
git commit -m "Add hero banner design"Git handles the conversion transparently. No special commands needed after the initial setup. The pointer file goes into your repository; the binary stays on the LFS server.
A real example from a travel platform: we track all destination photography at assets/photos/**/*.jpg with LFS. Marketing uploads a 200 MB batch of high-res photos. With standard Git, every developer's clone would bloat by 200 MB. With LFS, it's a 5 KB pointer per file.
Storage and Bandwidth Quotas Apply
LFS isn't unlimited. Understanding quota limits prevents surprises during deployments or CI/CD runs.
GitHub LFS quotas:
- Free tier: 1 GB storage, 1 GB bandwidth per month
- Pro/Team: 100 GB storage, 100 GB bandwidth per month (with ability to purchase more)
- Enterprise: Custom quotas
Bandwidth counts when you download files. A CI/CD pipeline that pulls large models, runs them, and uploads results can burn through bandwidth fast. A machine learning pipeline we built for a trading platform was downloading 50 GB of training data per build—that's 50 builds a month for the free tier's entire budget.
To track usage, monitor your LFS dashboard on GitHub or run:
git lfs ls-filesThis shows all files tracked by LFS and their sizes. Example output:
4d7a214614 * models/transformer-v2.onnx (487.3 MB)
8c9e2d4a5b * datasets/training-2024-01.sql (156.2 MB)
3f1e9c7b2a * assets/video-promo.mp4 (98.5 MB)For teams regularly exceeding quotas, consider:
- Gitea with S3 backend: Self-hosted, unlimited, pay only for S3 storage
- GitLab with custom object storage: Define your own quota ceiling
- Azure Artifacts or AWS CodeArtifact: Integrate LFS with enterprise repositories
We've migrated clients to self-hosted Gitea when LFS costs exceeded $500/month. S3 storage for the same 2 TB costs about $40/month, with bandwidth at $0.09 per GB downloaded.
Use for Design Assets and Media
LFS shines in scenarios where binary files are genuinely large and team members work with them regularly.
Real production examples:
E-commerce platform: A product photography workflow stores thousands of high-resolution images (15–50 MB each). Without LFS, the repository hit 12 GB within six months. With LFS patterns tracking *.jpg, *.png, and *.tiff, the repository stayed under 300 MB. Photography team members pull only the images they need; build servers pull everything once per deployment.
SaaS design system: A design team works in Figma and exports components as .sketch files (100–800 MB each). Designers regularly commit updated components. With LFS, commits are instant (pointer only), and designers pull the latest design files only when they open the repo in their design tool.
ML platform: Models in ONNX, SavedModel, or PyTorch formats (500 MB–5 GB) need versioning alongside code. Training pipelines produce new model checkpoints daily. LFS tracks *.onnx, *.h5, and *.pkl. CI/CD systems pull only the production model needed for inference tests, not the full training history.
Video platform: Demo videos, onboarding tutorials, and marketing materials live in the same repository as code. A 30-second HD video is 150–300 MB. LFS tracks *.mp4 and *.mov. Developers clone without downloading all videos; the front-end build process fetches only the production-ready exports.
Database snapshots for development: A trading platform maintains anonymized production database dumps for local development and staging. A 2 GB dump is committed monthly. LFS tracks *.sql and *.dump. New developers can clone the repo in seconds and pull the database dump separately when they need it.
Common Mistakes
1. Forgetting to install Git LFS before cloning: If you clone without git lfs install, you'll get pointer files instead of actual binaries. Fix it by running git lfs install, then git lfs pull.
2. Adding .gitattributes after committing large files: If you committed a 500 MB video before setting up LFS, adding the pattern to .gitattributes doesn't retroactively convert it. You need git lfs migrate import --include="*.mp4" to rewrite history. This is disruptive for teams, so plan LFS early.
2. Not tracking .gitattributes itself: .gitattributes must be committed and pushed. If it lives only locally, teammates won't have the LFS patterns and will commit full files to Git.
4. Running out of bandwidth mid-build: A CI/CD pipeline that pulls 50 GB of data can exhaust quotas quickly. Calculate your bandwidth needs: if builds pull 100 GB and you run 10 builds a day, budget 1 TB/month. Plan accordingly or switch to self-hosted LFS.
5. Mixing binary and text in the same file type: If you track *.db as LFS, but some team members commit SQLite databases while others commit JSON exports, you'll have consistency issues. Define patterns narrowly or enforce file naming conventions.
Key Takeaways
- Git LFS stores binary content on remote servers and commits pointer files instead, keeping repositories lean and clone times fast.
- Define patterns in
.gitattributesonce; Git applies LFS automatically to matching files from that point forward. - GitHub's free tier offers 1 GB storage and 1 GB bandwidth monthly; self-hosted options like Gitea with S3 are cost-effective at scale.
- Use LFS for design files, video, high-resolution images, ML models, and database dumps—files larger than a few MB that your team touches regularly.
- Set up LFS before committing large files; migrating existing history is disruptive and requires force-pushing.
- Monitor quota usage with
git lfs ls-filesand plan bandwidth around your build frequency.






Comments
Loading comments…