cloudparts

Git LFS

Git Large File Storage, a Git extension that commits small pointer files in place of large files and keeps their contents on a separate LFS server, downloading them only when a version is checked out.

What it is
Version control
Type
Open source
Made by
GitHub and Git LFS contributors
License
MIT
Facts checked
20 October 2026

What it is

Git keeps every version of every file in every clone, which is impractical for large binaries such as audio, video, datasets and graphics. Git LFS is a separate git-lfs program, written in Go, that hooks into stock Git through its clean and smudge filters. git lfs track writes a pattern such as *.psd to .gitattributes. When you git add a matching file, the clean filter hashes it with SHA-256, stores the contents in .git/lfs/objects, and hands Git a pointer file instead: three lines giving the spec version, the oid and the size, under 1024 bytes. Git commits, branches and merges the pointer like any small text file.

The contents travel separately. On git push, a pre-push hook first uploads any new large files to the LFS server, which by default lives at the Git remote’s URL plus .git/info/lfs; requests go through a JSON batch API over HTTP. On checkout, the smudge filter swaps each pointer for the real file, downloading it if it isn’t already local, so a clone fetches the large files for the version you check out rather than for all of history. Version 2.0 (March 2017) added file locking: git lfs lock marks a file as locked on the server, and pushes that modify files locked by someone else are refused, which helps with files that can’t be merged.

GitHub announced Git LFS in April 2015 and released it under the MIT license; GitLab supported it from November 2015, and its pointer format and server API are documented so that other servers and tools can implement them. A two-person core team runs the project today. The latest release is 3.8.0 (August 27, 2026), which adds zstd-compressed downloads.

Why teams pick it

  • Repositories stay small: Git history holds only pointers, and the large files are downloaded for the versions you actually check out
  • Works with stock Git and the usual commands: after git lfs install and git lfs track, git add, commit and push behave as before
  • File locking for files that are difficult to merge, such as binaries
  • Existing repositories can be converted with git lfs migrate import, and converted back with git lfs migrate export

Watch out for

  • Everyone needs it installed: without it a clone has pointer files instead of content, and a commit made without it stores the full file in Git, leaving files that always show as modified
  • Tracking a pattern doesn’t change existing history; moving old files into LFS with git lfs migrate rewrites commits and changes their hashes
  • The server must support LFS, and hosts may charge for its storage and bandwidth: GitHub launched it with 1 GB of free storage and 1 GB of monthly bandwidth
  • Files are chosen by path pattern only, not by size, so new large files of other types slip into Git unless someone tracks them

How it fits with other technologies

Track a file type, then see what Git really stores · bash

git lfs install                     # once per user: set up the clean and smudge filters
git lfs track '*.psd'               # writes the pattern to .gitattributes
git add .gitattributes design.psd
git commit -m 'Add design'

git cat-file -p HEAD:design.psd     # Git holds only the pointer:
# version https://git-lfs.github.com/spec/v1
# oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
# size 12345

git push                            # the pre-push hook uploads design.psd first
git lfs lock design.psd             # others can't push changes to it until you unlock

GIT_LFS_SKIP_SMUDGE=1 git clone <url> repo && cd repo && git lfs pull   # pointers first, then contents
git lfs migrate import --everything --include='*.zip'                   # rewrite history to move old files in

See it in a real stack

No architecture uses Git LFS yet. Drop it into the playground and wire it up yourself.Open playground →
Where it came from2013–2026

Distributed version control, as GitHub put it at launch, hadn’t always been practical for large files: every clone carries every version of every file. GitHub’s Risk Olson (@technoweenie) opened the project’s public repository in September 2013 from an internal prototype, and pre-release versions wrote pointer files with a hawser.github.com URL, which Git LFS can still read.

GitHub announced Git Large File Storage on April 8, 2015, as an open-source extension under the MIT license, with early access on GitHub.com, 1 GB of free storage and 1 GB of monthly bandwidth, and more for purchase. Version 0.6 that September added the batch API, so a client asks for many objects in one request, and 1.0 followed on October 1, 2015. On November 23, GitLab announced support on GitLab.com and in GitLab 8.2.

Version 2.0 in March 2017 added file locking, after a year of discussion, for teams editing files that are hard to merge. 3.0 in September 2021 added a pure SSH transfer protocol, though at the time no major forge was known to support it. The project is still led by a small core team, and 3.8.0 in August 2026 added zstd-compressed downloads and official packages for Debian 13.

Why it’s built this way

Pointer files inside ordinary Git
Instead of changing Git, Git LFS swaps the large file for a small text pointer and uses Git’s own clean and smudge filters and .gitattributes. Repositories stay valid Git, and every Git command and host keeps working on them.
Contents on a separate HTTP server, fetched on checkout
Keeping file contents out of the object database means a clone carries only the pointers in history. The smudge filter downloads a file’s contents only when that version is checked out, and the server is found from the Git remote’s URL so it needs little configuration.
An open specification
The pointer format and the batch API are documented as a guide for clients and servers, so other hosts and tools could implement them; GitLab shipped support seven months after the announcement.
Locking for files that can’t be merged
Some files, binaries especially, are difficult to merge, so two people shouldn’t edit one at the same time. Locks on the LFS server let teams claim a file, and pushes that change a file locked by someone else are refused.

Timeline

  1. 2013

    Public repository started from an internal GitHub prototype (September 22)

  2. 2015

    Announced by GitHub (April 8); batch API in 0.6 (September); 1.0 (October 1); GitLab support (November 23)

  3. 2017

    Git LFS 2.0 adds file locking (March 1)

  4. 2021

    Git LFS 3.0 adds a pure SSH transfer protocol (September 24)

  5. 2026

    Git LFS 3.8.0 adds zstd-compressed downloads (August 27)

Sources12 · facts checked 20 October 2026

Improve this page on GitHub