Sparse Checkout
Sparse checkout lets you check out only a subset of files from a repository into your working directory. Instead of materializing every file from every directory onto disk, Git writes only the paths you specify. The full history and all objects remain in the repository — but your working tree contains only what you asked for. This is a game-changer for large monorepos where a developer working on one package has no reason to have the other 200 packages on disk.
Why Sparse Checkout Exists
Modern monorepos can contain hundreds of packages, services, libraries, and platform-specific apps. A frontend developer working on packages/ui does not need the iOS app, the Kubernetes configs, or the machine-learning pipelines. Checking out all of those files wastes disk space and slows down every tool that scans the working directory — editors, linters, test runners, build systems, and file watchers. Sparse checkout fixes this by limiting the working tree to just the paths you actually need.
Cone Mode vs Non-Cone Mode
Feature | Cone Mode (recommended) | Non-Cone Mode |
|---|---|---|
Pattern format | Directory prefixes only | Full gitignore-style patterns |
Performance | Very fast — hash set lookup | Slower — pattern matching per path |
Complexity | Simple and predictable | Flexible but complex |
Enabled with | git sparse-checkout init --cone | git sparse-checkout init (no --cone) |
Supports wildcards | No | Yes (*.ts, **/tests/, etc.) |
Recommended for | Monorepo work, CI pipelines | Complex filtering with wildcards |
Enabling Sparse Checkout (Cone Mode)
Clone and initialize sparse checkout
# Clone the repository normally first git clone git@github.com:org/big-monorepo.git cd big-monorepo # Enable sparse checkout in cone mode git sparse-checkout init --cone # Check the working tree — only root-level files are present ls
Working tree after init --cone (root files only)
README.md package.json turbo.json .gitignore .eslintrc.json
After init --cone, only the files at the root of the repository are checked out. All subdirectories have been removed from your working tree but remain intact in the Git object store — nothing is lost.
Setting Paths to Include
Check out specific directories
# Check out packages/ui and docs/ git sparse-checkout set packages/ui docs/ # The working tree now contains: # - all root-level files (always included in cone mode) # - packages/ui/ and all its contents # - docs/ and all its contents ls packages/ # ui/
Adding More Paths
Add additional directories without replacing existing ones
# Add packages/shared to the existing sparse set git sparse-checkout add packages/shared # Add multiple paths at once git sparse-checkout add packages/api services/auth # Verify what is now included git sparse-checkout list
Output of git sparse-checkout list
docs packages/api packages/shared packages/ui services/auth
Disabling Sparse Checkout
To return to a full checkout with all files present, disable sparse checkout. Git will populate every file that exists in the current ref.
Disable sparse checkout and restore all files
git sparse-checkout disable # All directories are now visible ls packages/ # android/ api/ dashboard/ ios/ ml-models/ shared/ ui/ web/
Non-Cone Mode with Patterns
If you need wildcard patterns — for example all TypeScript source files, or all directories named tests — use non-cone mode. Patterns follow the same syntax as .gitignore files but with inverted semantics (lines specify what to include, not exclude).
Non-cone mode with gitignore-style patterns
# Initialize without --cone flag git sparse-checkout init # Patterns are written to .git/info/sparse-checkout # Include everything at root, exclude all of packages/, re-include packages/ui/ git sparse-checkout set '/*' '!/packages/' '/packages/ui/' # Inspect the pattern file cat .git/info/sparse-checkout
.git/info/sparse-checkout file contents
/* !/packages/ /packages/ui/
Real Use Case: Monorepo Developer Setup
Example monorepo structure
big-monorepo/ ├── README.md ├── package.json ├── turbo.json ├── packages/ │ ├── android/ ← you do not need this │ ├── api/ ← you need this │ ├── ios/ ← you do not need this │ ├── ml-models/ ← you do not need this │ ├── shared/ ← you need this │ └── ui/ ← you need this ├── services/ │ ├── auth/ ← you need this │ ├── billing/ ← you do not need this │ └── notifications/ ← you do not need this └── docs/ ← you need this
Set up sparse checkout for a frontend developer
git sparse-checkout init --cone git sparse-checkout set packages/api packages/shared packages/ui services/auth docs # Working tree is now only ~15% of the full repo size du -sh .
Combining Sparse Checkout with Shallow Clone
For the fastest possible repository initialization — minimal history AND minimal files — combine --depth=1 with sparse checkout. This is ideal for CI/CD pipelines working on monorepos where neither full history nor all packages are needed.
Maximum speed: shallow clone plus sparse checkout
# 1. Clone with depth=1 and skip the initial file checkout git clone --depth=1 --no-checkout git@github.com:org/big-monorepo.git cd big-monorepo # 2. Enable sparse checkout git sparse-checkout init --cone # 3. Set the paths you need git sparse-checkout set packages/ui packages/shared # 4. Perform the checkout git checkout main
Size comparison
Full clone (all history, all files): 2.1 GB 4m 20s Shallow clone (1 commit, all files): 340 MB 40s Shallow + sparse (1 commit, 2 packages): 48 MB 8s
Common Errors
Files appear missing but git status shows nothing — sparse checkout is hiding them. Run git sparse-checkout list to see active paths.
"error: pathspec did not match any files" — the path you specified does not exist in the repository at the current branch.
Build tool reports missing packages — your build references a package not in your sparse set. Add it with git sparse-checkout add packages/missing.
After switching branches, files disappear — the new branch may have a different directory layout. Re-run git sparse-checkout set with correct paths.