git-unlimited-storage
Turn a private GitHub repository into a real file storage backend.
No S3. No Cloudflare R2. No Cloudinary. No card on file. No monthly bill.
---
Every application needs somewhere to put uploaded files. The default answer is an
object store, a billing account, an access key policy and a bill that arrives
whether or not anyone visited your site this month.
There is another answer. A GitHub repository is already a content addressed
object database with an HTTP API in front of it, and you already have unlimited
private repositories. This project is the production grade version of that idea,
extracted from a live application and rewritten so anyone can drop it in.
Two implementations, Python and Node, same behaviour, no runtime dependencies
worth the name.
> ### Read this before you write any code
>
> **The storage repository must be private.**
>
> A public repository is world readable, crawlable, forkable and permanent. Every
> user upload you place in one is exposed the moment it lands, and switching the
> repository to private afterwards does not recall the copies that already exist.
>
> This library refuses to start against a public repository unless you explicitly
> declare that you meant it. `gitstore doctor` checks it in one command, and
> belongs in your CI pipeline.
---
## Contents
- [Why this exists](#why-this-exists)
- [What you get](#what-you-get)
- [Quick start: Python](#quick-start-python)
- [Quick start: Node.js](#quick-start-nodejs)
- [How it works](#how-it-works)
- [Serving files to browsers](#serving-files-to-browsers)
- [What it costs](#what-it-costs)
- [Honest limits](#honest-limits)
- [Security](#security)
- [Documentation](#documentation)
- [Questions people ask](#questions-people-ask)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
---
## Why this exists
The pattern comes out of a production application that needed image and document
storage on a budget of zero. It has been serving avatars, galleries, generated
reports and verification documents from a private repository, behind an
authenticated proxy, without a storage bill.
The interesting part was never the upload call. It was everything around it: the
validation that stops a PHP script wearing a `.jpg` extension, the key layout that
does not collapse at a hundred thousand files, the write serialization that GitHub
quietly requires, the batching that turns fifty commits into one, and the serving
layer that keeps the token out of the browser.
That is what is packaged here, with the application specific parts removed.
## What you get
| | |
| --- | --- |
| **Magic byte validation** | Formats detected from the bytes, never from the extension or the declared type. SVG rejected on purpose. Polyglot files carrying `