Ripgit is one of the more interesting projects in the growing Cloudflare application ecosystem.
Most Git self-hosting discussions start with a VPS and end with something like Forgejo, Gitea, GitLab CE, or a bare Git server behind SSH.
Ripgit takes a different path: it stores Git repositories inside Cloudflare Durable Objects, runs the application as a Cloudflare Worker, and exposes a standard Git-over-HTTP remote.
That makes it self-hostable, but not in the old Docker-on-a-server sense.
What is Ripgit?
Ripgit is:
“A self-hostable git remote backed by Cloudflare Durable Objects.”
The core idea is simple:
one repository = one Durable Object
Each repository gets isolated Durable Object state with SQLite storage. Ripgit then implements enough of the Git smart HTTP protocol for normal workflows such as:
git remote add origin https://your-worker.workers.dev/username/myproject
git push origin main
git clone https://your-worker.workers.dev/username/myproject
It is not just an object bucket. The repo includes a web UI, code browser, commit pages, diffs, full-text search, raw file serving, issues, pull requests, and JSON/text APIs.
Can Ripgit Be Self-Hosted?
Yes, but the word self-hosted needs precision here.
Ripgit can be deployed into your own Cloudflare account. You control the Worker, Durable Object namespace, KV namespaces, routes, secrets, and optional auth worker.
That is self-hosting in the Cloudflare-native/serverless sense.
It is not self-hosting in the Forgejo sense, where you run a container or binary on a homelab machine and back up a local volume.
If you want that distinction in more detail, this post pairs well with the earlier Cloudflare Workers, D1, KV, and R2 serverless stack overview.
Tech Overview
Ripgit’s main worker is written in Rust using workers-rs.
The interesting components are:
| Component | What it does |
|---|---|
| Cloudflare Worker | Routes browser, API, and Git HTTP requests |
| Durable Objects | One stateful object per repository |
| Durable Object SQLite | Stores refs, commits, trees, blobs, issues, PRs, search indexes |
| Cloudflare KV | Stores repository registry entries for owner profile pages |
| Optional auth Worker | Handles GitHub OAuth, browser sessions, and long-lived Git tokens |
| Service Binding | Lets the auth worker call the Ripgit worker privately |
| SQLite FTS5 | Powers code and commit-message search |
| xpatch + zlib | Stores changed blob versions efficiently |
The local schema includes tables for Git refs, commits, commit parents, tree entries, blob groups, blob chunks, raw objects, config, issues, issue comments, and FTS5 indexes.
That explains the main tradeoff. Ripgit is compact because it uses Cloudflare’s platform primitives directly. It is also platform-specific for the same reason.
What You Get
Ripgit supports standard Git-over-HTTP paths for pushing, cloning, and fetching.
It also exposes a useful set of web and API routes:
/:owner/
/:owner/:repo/
/:owner/:repo/commits
/:owner/:repo/commit/:sha
/:owner/:repo/tree/:ref/*path
/:owner/:repo/blob/:ref/*path
/:owner/:repo/raw/:ref/*path
/:owner/:repo/search-ui
/:owner/:repo/issues
/:owner/:repo/pulls
/:owner/:repo/settings
For programmatic use, the JSON API includes refs, logs, commits, trees, blobs, files, search, diffs, comparisons, and stats:
curl https://your-worker.example/alice/project/refs
curl "https://your-worker.example/alice/project/log?ref=main&limit=50"
curl "https://your-worker.example/alice/project/search?q=TODO"
curl https://your-worker.example/alice/project/stats
Many browser pages also support markdown or plain-text negotiation:
curl -H "Accept: text/markdown" https://your-worker.example/alice/project/
curl -H "Accept: text/plain" https://your-worker.example/alice/project/settings
curl "https://your-worker.example/alice/project/?format=md"
That agent-friendly design is one of Ripgit’s strongest differentiators. A coding agent, shell script, or terminal workflow can inspect a repository without scraping HTML.
Deployment Shape
The root wrangler.toml defines:
name = "ripgit"
main = "build/index.js"
compatibility_date = "2026-03-18"
[[kv_namespaces]]
binding = "REGISTRY"
[durable_objects]
bindings = [
{ name = "REPOSITORY", class_name = "Repository" }
]
[[migrations]]
tag = "v1"
new_sqlite_classes = ["Repository"]
The basic deploy flow is:
git clone https://github.com/deathbyknowledge/ripgit
cd ripgit
wrangler kv namespace create REGISTRY
# paste the generated namespace ID into wrangler.toml
wrangler deploy
For a real deployment, you should put the GitHub OAuth example worker in front of it.
cd examples/github-oauth
npm install
wrangler kv namespace create OAUTH_KV
wrangler kv namespace create OAUTH_KV --preview
wrangler secret put GITHUB_CLIENT_SECRET
wrangler secret put SESSION_SECRET
wrangler deploy
The auth worker needs:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETSESSION_SECRETOAUTH_KV- a
RIPGITService Binding pointing to the main Ripgit Worker
Important: the README warns that if you deploy the main Ripgit worker without an auth worker in front of it, repositories are publicly readable and writable by anyone who knows the URL.
Field Note: Local Trial
I cloned the repository locally at commit 21dba30423a38f0ecb5a9e2ce79bbfc4f2d36669.
This machine had:
Node.js v18.19.1
npm 9.2.0
rustc 1.75.0
cargo 1.75.0
Root npm install completed, and the OAuth worker TypeScript check passed:
cd examples/github-oauth
npm install
npm run typecheck
The main worker did not build on this host because the available toolchain is too old:
cargo checkfailed becauseCargo.lockuses lockfile version 4.npm testfailed while installing/buildingworker-build, because current crates require newer Cargo support.npx wrangler --versionfailed because current Wrangler requires Node.js 20+, while this host has Node.js 18.
So the practical prerequisite is: use Node.js 20+ and a current Rust/Cargo toolchain before trying local Miniflare tests or deployment.
Ripgit vs Forgejo
Ripgit and Forgejo both host Git repositories, but they are not trying to be the same product.
| Question | Ripgit | Forgejo |
|---|---|---|
| How do I run it? | Cloudflare Workers, Durable Objects, KV | Docker, binary, VPS, homelab, Kubernetes |
| Is there a normal Docker Compose setup? | No | Yes |
| Where is repo data stored? | Durable Object SQLite | Local disk plus SQLite/Postgres/MySQL |
| Git over SSH? | No clear SSH support; Git-over-HTTP is the target | Yes |
| Built-in user/admin system? | Minimal; use an upstream auth worker | Yes |
| Issues and pull requests? | Yes, lightweight implementation | Yes, mature forge workflow |
| CI/CD? | Not built in | Forgejo Actions |
| Package registry? | Not built in | Yes |
| Best use case | Cloudflare-native Git remote, agent-friendly repo publishing, small edge-hosted Git service | Full self-hosted GitHub/Gitea alternative |
Use Forgejo if you want a complete self-hosted software forge: users, orgs, SSH, protected workflows, package registry, webhooks, CI runners, admin settings, backups, and conventional server ownership.
Use Ripgit if the interesting part is the architecture itself: Git hosting without a VPS, per-repository Durable Objects, low server maintenance, and API/text-first repository access.
When I Would Pick Ripgit
Ripgit makes sense when:
- you are already comfortable with Cloudflare Workers;
- you want to experiment with Git repositories as edge-native objects;
- your repositories are small or moderate;
- you want HTTP APIs and markdown/plain-text views for scripts or agents;
- you do not need a full organization-scale forge;
- Cloudflare platform lock-in is acceptable.
I would not use it as my main Forgejo replacement yet for a team that depends on mature Git forge features every day.
I would use it as a fascinating Cloudflare-native Git remote, especially for agent-facing repositories, public code mirrors, small project publishing, and experiments around serverless developer infrastructure.
FAQ
Is Ripgit self-hostable?
Yes, but it is Cloudflare-native self-hosting. You deploy it into your own Cloudflare account using Workers, Durable Objects, KV, and optional Service Bindings.
It is not a normal Docker app you run on a VPS. If you want a portable Linux/container forge, use Forgejo instead.
Can I run Ripgit fully locally?
Not as a normal production stack. You can use Wrangler and local Cloudflare development tooling for development, but the production architecture depends on Cloudflare Workers, Durable Objects, KV, and Service Bindings.
For this local trial, the worker could not be run because the host had Node.js 18 and Rust 1.75. Current Wrangler expects Node.js 20+, and the Rust dependency chain expects a newer Cargo toolchain.
Does Ripgit have a UI?
Yes. It has a lightweight repository UI with owner pages, repo home pages, file tree browsing, blob viewing, commit history, diffs, search, raw files, settings, issues, and pull requests.
It is not as complete as Forgejo’s UI, but it is much more than a bare Git storage endpoint.
What Cloudflare services does Ripgit use?
The main app uses Workers for compute, Durable Objects for per-repository state, Durable Object SQLite for repository storage, and KV for the repository registry.
The GitHub OAuth example adds a second Worker, an OAUTH_KV namespace for OAuth/session/token state, Worker secrets for GitHub/session credentials, and a Service Binding to call the main Ripgit worker privately.
What happens if I deploy Ripgit without the auth worker?
Do not expose that casually.
The upstream README states that without the auth worker, repositories are publicly readable and writable by anyone with the URL. For a real instance, put the auth worker in front and only trust X-Ripgit-Actor-* headers that arrive through a Service Binding.
Is Ripgit better than Forgejo?
It is different.
Forgejo is the better answer if you want a mature self-hosted GitHub/Gitea alternative on your own server. Ripgit is more interesting if you want Git hosting that lives inside Cloudflare’s serverless runtime and exposes agent-friendly APIs.
For most homelabs, Forgejo is still the practical Git forge. For Cloudflare-native experiments, Ripgit is the more unusual project.
What are the main limits?
The README calls out large push timeouts around very high object counts, Cloudflare’s request body limit, non-mature force-push behavior, and lack of annotated tag support.
The practical operational limit is also architectural: your backups, quotas, runtime, and storage model are Cloudflare-specific.
Comments