Managing Large Binaries on GitHub — Git LFS and Its Alternatives Compared at 10 GB, 100 GB, and 1000 GB

Tadashi Shigeoka · Fri, July 24, 2026

Trained models, game assets, build artifacts, sample datasets. As a project matures, the binaries it wants to keep near source code tend to grow by an order of magnitude at a time: 10 GB, then 100 GB, then 1 TB. Plain Git and GitHub are fundamentally optimized for versioning text, and a push is rejected once a single file crosses 100 MiB.

The uncomfortable part is that reaching for Git LFS does not automatically solve this. LFS is perfectly viable at 10 GB, starts breaking down past 100 GB, and by 1 TB an object-storage bridge is essentially mandatory. This post lines up six practical options against July 2026 docs and pricing, and compares them at three scales: 10 GB, 100 GB, and 1000 GB.

What you will get from this article

  • Concrete numbers for GitHub’s plain-Git limits (50 MiB warning, 100 MiB block, ~1 GB recommended repo size)
  • Git LFS’s billing model (metered, with free tiers) and the two structural reasons the bill spikes
  • Where GitHub Releases, Cloudflare R2 with a self-hosted LFS proxy, DVC, AWS S3, and Hugging Face Hub each fit
  • Which options survive at 10 GB, 100 GB, and 1000 GB, with a monthly cost per row

GitHub’s Plain-Git Limits

Before touching LFS, pin down what vanilla Git-on-GitHub actually accepts. The primary source is GitHub Docs: About large files on GitHub.

  • Files over 50 MiB trigger a push warning
  • Files over 100 MiB are hard-blocked (git push is rejected)
  • Web UI uploads cap at 25 MiB per file
  • A single git push has a hard 2 GiB ceiling
  • Repositories are recommended to stay under 1 GB; above 5 GB you may hear from GitHub support

By the time you reach the 10 GB range, plain Git is no longer viable. That is the fork: LFS, Releases, or an external store.

Git LFS: Billing Model and Per-Plan Caps

Git LFS keeps the payload in a separate LFS store and leaves a tiny pointer in Git. Per GitHub Docs on LFS billing, the model migrated from prepaid “data packs” (50 GB for USD 5) to fully metered billing between 2023 and 2025.

Free tiers and overage rates land like this:

PlanIncluded storageIncluded bandwidth/monthMax single file
GitHub Free10 GiB10 GiB2 GB
GitHub Pro10 GiB10 GiB2 GB
GitHub Team250 GiB250 GiB4 GB
GitHub Enterprise Cloud250 GiB250 GiB5 GB

Overages cost 0.07 USD/GiB-month for storage and 0.0875 USD/GiB for bandwidth. If you leave the spending limit at the default 0 USD, LFS operations get blocked as soon as you cross the free tier, and reset on the first of the following month.

The per-file cap is worth flagging. Anything over 5 GB in a single file is rejected even by LFS. At the 1 TB total-size scale, individual files typically still fit under 5 GB, so this rarely bites in practice; the exception is a single 8 GB model checkpoint you want to store whole, at which point LFS is off the table entirely.

The Two Structural Reasons the LFS Bill Spikes

So why does Git LFS have the reputation of surprise bills? Two reasons.

Bandwidth Gets Billed to the Repository Owner

In GitHub’s billing model, every LFS download counts against the repository owner’s bandwidth quota. Public or private, forks, GitHub Actions CI jobs, external CDNs that periodically fetch: they all draw down the owner’s allowance.

If CI has no cache and redownloads LFS every run, this bandwidth grows linearly with storage size. Running CI 100 times a month against a 100 GB LFS store produces 10 TB of transfer, which lands around USD 800 in the cost table below.

Storage Accumulates by History, Not by Snapshot

Git LFS does not diff binaries. Change one byte and push, and a brand-new full-size object gets stored. Update 100 GB of data four times in a month and 400 GB is sitting in the LFS backend by month end.

Storage keeps growing until you explicitly prune with git lfs prune. Regularly retrained models and CI-driven auto-updates compound this fast.

Five Alternative Patterns

Beyond native GitHub LFS, five options cover most realistic use cases across scales.

GitHub Releases

When the file is a build artifact or a frozen distribution archive rather than something that changes with every source edit, GitHub Releases is the cleanest fit.

  • Up to 1,000 assets per release, each under 2 GiB
  • No cap on total release size, no bandwidth charge
  • Assets never enter a git clone, so clones stay lean

At 100 GB or even 1 TB you can still work with Releases by splitting the archive with split into ~1.9 GiB parts. With 1,000 assets per release, a single tag can hold nearly 1.9 TB in theory. GitHub CLI’s gh release create and gh release download make this scriptable.

The free bandwidth is the big win on the distribution side. Versioning happens at tag granularity, and assets do not appear in the working tree, so this suits cases where you want source and artifacts kept separate.

Self-Hosted LFS Proxy + Cloudflare R2

Git LFS is an open Batch API, and the server that stores the actual objects is swappable. Point .lfsconfig at a different endpoint and the developer experience (git push, git pull) stays the same while the payload lands elsewhere.

The common recipe is a small proxy such as git-lfs-s3-proxy on Cloudflare Workers, backed by Cloudflare R2. R2 pricing:

  • Storage 0.015 USD/GB-month (first 10 GB free)
  • Egress is free, always
  • Class A operations 4.50 USD per million, Class B 0.36 USD per million

Because egress is free, downloading 1 TB ten times a month (10 TB of transfer) only costs the storage fee. That completely defuses GitHub-native LFS bandwidth billing, which is the biggest win of this pattern. Backblaze B2 is a close cousin: free egress up to three times your average monthly stored data, and 0.01 USD/GB above that.

The catch is operations. Auth on the proxy and any credentials that end up embedded in URLs are your responsibility. Get that wrong and the bucket becomes world-readable, so IAM least-privilege and short-lived signed URLs are non-negotiable.

DVC + Object Storage

For machine learning datasets, model weights, and pipeline intermediates, DVC (Data Version Control) is a strong fit. DVC is an OSS CLI that overlays on Git: Git tracks a small .dvc pointer file, and the real payload syncs to any remote you configure, including S3, Google Cloud Storage, Cloudflare R2, and Google Drive.

What DVC does over LFS is reproducibility of the whole pipeline. Declare stages (preprocess, train, evaluate) in dvc.yaml, and dvc repro re-runs the changed ones. It also composes cleanly with GitHub Actions via setup-dvc.

Cost depends on the backend. R2 keeps 100 GB in the single-digit USD range. S3 Standard is 0.023 USD/GB-month plus egress (roughly 0.09 USD/GB from US East). The team pays the cost of learning dvc push / dvc pull and folding them into the workflow. For ML the payoff is clearly worth it; for generic binary distribution it is overkill.

Note that DVC’s OSS project moved to Treeverse, the company behind lakeFS, in late 2025. The roadmap there is worth keeping an eye on.

git-annex and git-remote-s3

Two OSS tools generalize “metadata in Git, payload outside”: git-annex and git-remote-s3.

git-annex stores payload in a “special remote” and only a reference in Git. Special remotes cover S3, rsync, USB drives, offline media, IPFS, and more. It shines for distributed setups, archives, and long-term preservation. The tradeoff is a distinct command set (git annex add / get / copy / sync) that pulls quite far from the plain GitHub experience.

git-remote-s3 (AWS Labs) treats an S3 bucket as a Git remote and an LFS server. It composes well with IAM least-privilege and SSE-KMS, which matters when the requirement is “keep this off GitHub and inside our AWS account.”

Hugging Face Hub, Zenodo, and Direct Object Store References

If the artifact’s audience is well-defined, purpose-built hosting is usually the first choice.

  • ML models and datasets: Hugging Face Hub offers effectively unlimited public storage, free egress, and free CDN, backed by content-defined chunking via Xet (formerly XetHub) for deduplicated uploads
  • Research data with a DOI requirement: Zenodo accepts up to 50 GB per record for free, and integrates with GitHub to auto-archive on release
  • Game or web assets where the app fetches from a URL anyway: keep an assets.json in Git and drop the payload directly into R2 or S3. This “Git-less” pattern is the leanest option

Cost Compared by Scale

Fix one scenario and read the monthly cost across 10 GB / 100 GB / 1000 GB. Assumptions:

  • Storage = peak monthly stored size (includes accumulated history)
  • Monthly transfer = 10× stored size (mid-active team + CI mix)
  • S3 egress uses US East reference at 0.09 USD/GB, first 100 GB per month is free account-wide
Option10 GB / 100 GB transfer100 GB / 1000 GB transfer1000 GB / 10 TB transfer
GitHub LFS (Free/Pro)~7.88 USD~92.93 USD~943 USD
GitHub LFS (Team/Ent.)0 USD (in tier)~65.63 USD~906 USD
GitHub Releases0 USD0 USD (needs split)0 USD (needs split)
Self-hosted LFS proxy + Cloudflare R20 USD~1.35 USD~14.85 USD
AWS S3 Standard alone~0.23 USD~83.30 USD~914 USD
Hugging Face Hub (public)0 USD0 USD0 USD

Reading the table row by row: GitHub LFS Free/Pro is fine inside 10 GiB, but past that the 0.07 / 0.0875 USD overage rates compound linearly, pushing 100 GB into double digits and 1 TB into triple digits. Team and Enterprise Cloud get 250 GiB free, which absorbs the 100 GB scale, but at 1 TB the bandwidth overage lands near USD 900 anyway. Seat pricing (Team is 4 USD/user/month) is separate.

R2 and Hugging Face stay near zero because egress is free. R2 specifically is 0.015 USD/GB-month, so 1 TB is still under USD 15. S3 alone has a 100 GB per-month free egress tier, then 0.09 USD/GB, which is where projects with unpredictable transfer volumes see sudden bills.

Releases stays at 0 USD regardless of scale, at the cost of splitting into <2 GiB assets and not appearing in the working tree.

Choosing by Scale + Use Case

Reading the table by column reveals the decision points.

The 10 GB Scale

  • Solo or small team: stay on GitHub LFS. Free/Pro fits inside the 10 GiB tier and costs a few USD if bandwidth spikes
  • Distribution is the point: GitHub Releases. Split only when a single asset exceeds 2 GiB
  • Public ML models: Hugging Face Hub, at 0 USD

At 10 GB, the setup cost of an object-storage bridge tends to outweigh the savings. LFS or Releases is almost always the pragmatic choice. Building out an R2 backend starts paying off at the next tier up.

The 100 GB Scale

  • Team development where CI redownloads LFS every run: self-hosted LFS proxy + Cloudflare R2. A few USD/month, avoiding both Team seat pricing and the ~USD 66 bandwidth overage
  • Prefer plain operations: moving to GitHub Team can absorb this in the 250 GiB tier, but heavy CI easily pushes transfer past 1 TB, so plan for the next step
  • ML pipelines: bring in DVC + R2/S3 at this stage; no migration needed later at 1 TB
  • Distribution only: Releases is 0 USD regardless of size. Confirm the operational impact of 50+ split assets before committing

100 GB is the practical ceiling for staying on native Git LFS. Past this, bandwidth grows linearly and monthly bills at USD 100+ become plausible.

The 1000 GB / 1 TB Scale

  • Team development: essentially a single choice, self-hosted LFS proxy + Cloudflare R2. GitHub LFS Team/Enterprise runs USD 900/month, S3 alone runs USD 900/month, R2 stays at USD 15
  • ML pipelines: DVC + R2, or lakeFS on top of an S3 data lake
  • Game or media giga-binaries: Perforce Helix Core becomes a realistic option. You leave the Git ecosystem, but locking semantics and Unreal/Unity integration are much stronger

At 1 TB, native Git LFS breaks down on both cost and the per-plan effective bandwidth cap (250 GiB/month free). Make the “keep Git or leave Git” decision first; if you keep Git, the payload has to live in R2 or S3.

Thresholds That Change the Decision

Concrete thresholds where the implementation should change:

  • Any single file exceeds 5 GB: LFS is out entirely; split, or move to direct object-store references
  • Monthly bandwidth persistently over 250 GiB: the Team/Enterprise free tier saturates; move to an R2 backend
  • LFS storage crosses 100 GB: history accumulation is now a real cost; establish prune practice or migrate to DVC + external storage
  • CI redownloads LFS on every run: add a cache, or switch to R2

Wrap-Up

At 10 GB, GitHub LFS is fine. At 100 GB, a self-hosted LFS proxy + Cloudflare R2. At 1 TB, a broader design call between R2, DVC, and even Perforce. The same requirement (“keep large binaries near a GitHub repository”) has a different optimal answer at every order of magnitude. The two mechanics behind that are constant: bandwidth concentrates on the repository owner, and storage grows with history rather than snapshots. Keep both in view and you can plan the migrations before the bill forces them.

That’s all from comparing Git LFS with its alternatives at 10 GB, 100 GB, and 1 TB, from the Gemba.

References