Handling Large Files in CI: Optimization and Storage Strategies
Stop slowing down your builds. Learn how to manage large files in CI using Git LFS and external storage to keep your pipelines fast, lean, and reliable.

Previously in this course, we covered Automating Releases to handle versioning. This lesson adds a critical layer of performance: keeping your CI pipelines lean by effectively managing large files and assets that don't belong in your standard Git history.
The Problem with Large Files in Git
Git is designed to track changes in source code—typically text. When you add large binary files (like high-resolution images, compiled assets, or datasets) to your repository, you inflate the .git folder size for every developer and every CI runner.
Every time a runner executes git clone or git fetch, it must download the entire history of those large files. This leads to slow job initialization, massive network egress, and eventual pipeline timeouts. If your repo is bloated, your CI isn't just slow; it's fragile.
Strategy 1: Git LFS (Large File Storage)
Git LFS replaces large files in your repository with tiny "pointer files." The actual data is stored in a separate server, and the LFS client downloads the heavy content only when you explicitly need it.
Implementation Steps:
- Install LFS: Ensure it is installed on your local machine (
git lfs install). - Track Files: Define which files to track:
git lfs track "*.psd". - Commit the
.gitattributesfile: This file tells Git how to handle these extensions.
In GitHub Actions, you don't need to manually install LFS. The actions/checkout action handles it automatically if the repository is configured:
YAMLsteps: - name: Checkout code uses: actions/checkout@v4 with: lfs: true # This flag ensures the runner downloads the LFS objects
Strategy 2: External Storage for Non-Versioned Assets
If your "large files" are build artifacts, temporary datasets, or heavy dependencies that change frequently, do not put them in Git at all.
Instead, treat your repository as a source-only container and fetch assets from a dedicated storage service (like AWS S3, Google Cloud Storage, or an Artifactory instance) during the pipeline.
Worked Example: Fetching from External Storage
Suppose your application needs a 500MB pre-trained model file. Instead of committing it, write a script to fetch it only when the build runs:
YAMLsteps: - name: Download Model from S3 env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET }} run: | aws s3 cp s3://my-company-assets/model-v1.zip ./assets/ unzip ./assets/model-v1.zip -d ./assets/
This keeps your repository small (KB or MB) while your CI runner handles the heavy lifting only when necessary.
Comparison: When to use which?
| Scenario | Recommended Strategy | Why? |
|---|---|---|
| Game assets, icons, media | Git LFS | Versioning is required; files change rarely. |
| Build outputs, logs | Artifacts | Artifact Management is built for this. |
| Large datasets, ML models | External Storage | Keeps repo lean; avoids Git history bloat. |
| Dependencies (node_modules) | Caching | Advanced Pipeline Caching is faster. |
Hands-on Exercise: Optimize Your Repository
- Identify one file in your project that is larger than 5MB.
- If it is a static asset that needs versioning, use
git lfsto track it. - If it is a generated file or a large dataset, move it to an external storage bucket or a public URL, and update your
main.ymlto usecurlorwgetto fetch it during thebuildjob. - Verify that your
git clonetime remains under 10 seconds.
Common Pitfalls
- Forgetting
lfs: true: If you use LFS but forget thelfs: trueflag inactions/checkout, your build will receive the pointer file instead of the actual data, causing "file not found" errors in your build scripts. - Over-tracking: Don't track small files with LFS. It adds unnecessary complexity. Only use it for files that truly hinder cloning speeds.
- Public exposure: If you move files to external storage, ensure the bucket permissions are correctly scoped to your CI credentials; don't make them publicly readable if they contain proprietary data.
FAQ
Q: Does Git LFS count against my repository storage limit? A: Yes, GitHub provides a specific amount of storage and bandwidth for LFS, which is separate from your standard repository limit.
Q: Can I use both LFS and external storage? A: Absolutely. Use LFS for versioned assets tracked in the repo and external storage for dynamic, non-versioned, or massive files.
Q: Is caching better than LFS?
A: They serve different purposes. Caching is for transient data that can be re-generated (like node_modules). LFS is for static binary files that are part of your source code.
Recap
We've moved beyond simple code management by tackling the bloat that kills pipeline performance. By choosing between Git LFS for versioned assets and external storage for everything else, you ensure that your CI/CD environment stays fast and efficient.
Up next: Cross-Repository Workflows — learning how to trigger pipelines across different projects.
Work with me

CI/CD Pipeline & Docker Containerization
Ship with confidence: automated CI/CD pipelines and Docker setups so every push is tested and deployed — no more manual, error-prone releases.

Custom Email & File Storage System on Cloudflare (Google Workspace Alternative)
Your own private email + file storage suite on your domain — unlimited mailboxes, no per-seat fees. A self-owned Google Workspace alternative for a flat ~$5/month.


