How Git LFS pointer files and storage work in Azure Repos and GitHub, the limits on each platform and what pipelines need to fetch LFS content.
From Ultra Transcenders AZ-400 by Tony Rough (coming November 2026)
Large files hurt Git whether they’re text or binary, and most of all when they change often: delta compression stops working and Git stores nearly a full copy of every version, which every clone then downloads. The first decision is where each kind of file belongs.
| Content | Store in | Reason |
|---|---|---|
| Source code, scripts, text, structured data (JSON) | Git | Diffs and compresses well |
| Dependencies, libraries, reusable packages | Azure Artifacts or another package manager | Versioned, installed at build or deploy time |
| Build outputs, logs, traces, diagnostic data | Neither; publish as pipeline artifacts or share elsewhere | Generated content bloats history |
| Small, rarely changed binaries (icons, web images) | Git | Keeps one workflow; little growth |
| Large binaries that change often and don’t diff (video, audio, game maps) | Git LFS | Keeps full contents out of every clone |
Even small binaries cause problems if updated often: 100 changes to a 100 KB file use as much storage as 10 changes to a 1 MB file. Microsoft also advises not committing compressed archives (commit the uncompressed, diffable sources) and not moving many small files into LFS, which doesn’t help performance and can make it worse.
Git Large File Storage (LFS) stores a small pointer file in the repository and keeps the binary content in separate remote storage, downloading the right version on clone or checkout. The pointer has three lines: Figure 4.1 shows what a clone fetches with and without the LFS client.
version https://git-lfs.github.com/spec/v1
oid sha256:a747cfbbef63fc0a3f5ffca332ae486ee7bf77c1d1b9b2de02e261ef97d085fe
size 4923023
Tracking is configured per file pattern with git lfs track, which writes the pattern into .gitattributes. Commit .gitattributes to the repository so forks and fresh clones use the same tracking:
git lfs track "*.psd"
git add .gitattributes path/to/file.psd
git commit -m "Track PSD files with Git LFS"
git push
Existing large files already in history must be removed from the repository and re-added through LFS; tracking a pattern doesn’t rewrite past commits.
checkout step doesn’t download LFS content unless lfs: true is set, and self-hosted agents need git-lfs installed.| GitHub Git LFS | GitHub Free | GitHub Pro | GitHub Team | GitHub Enterprise Cloud |
|---|---|---|---|---|
| Maximum LFS file size | 2 GB | 2 GB | 4 GB | 5 GB |
| Included storage | 10 GiB | 10 GiB | 250 GiB | 250 GiB |
| Included bandwidth | 10 GiB | 10 GiB | 250 GiB | 250 GiB |
GitHub Free for organizations also includes 10 GiB of each. GitHub LFS is billed on metered usage, always against the repository owner (including downloads by forks and by GitHub Actions); every push of a changed LFS file stores a full new copy. Exceeding the storage quota without a payment method leaves clones with pointer files only and blocks pushing new files; exceeding bandwidth disables LFS on the account until the next month. Git LFS can’t be used with GitHub Pages sites or template repositories.
Common trap: Adding
.gitattributespatterns after the large files were committed and expecting the repository to shrink - tracking affects new commits only; existing blobs stay in history until removed.
Common trap: Moving every asset into LFS to speed things up - Microsoft says LFS is for large files that don’t diff well, and moving many small files into LFS can make performance worse.
This note is one section of Ultra Transcenders AZ-400: Designing and Implementing Microsoft DevOps Solutions, an independent study guide that explains every topic the exam covers by technology, with comparison tables, diagrams and the common traps, plus a glossary linked to Microsoft Learn.
Due on Amazon in November 2026, in Kindle and paperback editions.
About the book · AZ-400 terms in the glossary · All AZ-400 study notes
How trunk-based development, GitHub Flow, feature branches, release branches and forks differ, and which fits a team's release cadence.
How the two CI/CD platforms compare on hosting, YAML, integrations and licensing, and when to combine them.
Which agent or runner option fits private network access, custom software, scale and maintenance requirements.
How each release pattern limits risk, what it costs and how traffic or users move to the new version.
How @Local, @Prerelease and @Release views work, how promotion moves packages through them and who consumes each view.
When a pipeline should use a service principal, a system-assigned or a user-assigned managed identity, and the trade-offs of each.
The four DORA metrics, where to get the data in Azure DevOps and GitHub, and which metrics suit planning, development, testing, security, delivery and operations.