npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@superdisk/dumbforge

v0.1.0

Published

Push Git repositories to S3-compatible buckets and clone them over static dumb HTTP

Readme

dumbforge

the following text is not LLM generated

Well, everyone's been talking about GitHub alternatives lately. I'm pretty sympathetic to that on an ideological level (and just the fundamental problem of it being down all the time), but historically the alternatives kind of suck, and I think still miss the point of Git being decentralized in the first place. Gitea/Forgejo are cool, but require you to set up a server and configure it. Even though it's pretty easy, it's still annoying and requires you to pay for and babysit a VPS or whatever to run the forge program. Codeberg has been a platform of choice for freedom-heads to get away from GitHub, but they recently instituted a no-crypto and no-LLM rule. I respect what they're doing, but I'm pretty AI-pilled so that's not going to work for me.

It occurred to me that you don't actually need to run a forge or git daemon at all, since Git supports cloning via the so-called "dumb" HTTP protocol. You could theoretically just throw your git repo into an s3 bucket, and it would be clone-able, no daemon or VPS required. So that's cool, and even more decentralized; but the problem with self-hosting git like that, is that then you don't have the nice landing page, file browser, commit log, etc etc. It's small, but it makes a big difference to have a GitHubby UI for each project. SourceHut and Savannah struggle with this I think, since they're pretty alien to normies.

So I slopped dumbforge together as a proof of concept; it's a git remote helper that also functions as a static-site-generator-like-thing, which pushes directly to an s3 bucket, and generates a GitHub-like UI. So you get some really nice advantages:

  1. It's super fast to browse, since it's just static HTML. GitLab and GitHub itself are really slow clunky beasts.
  2. You don't need to administer a git daemon or forge server.
  3. It's free if you're storing less than 10 gigs, using CloudFlare R2.
  4. You're decentralized, bro! Well, mostly.

I'll grant that the implementation could most certainly use some improvement but this is mostly just to show off the idea. I hope it piques your curiosity. 🤔

If you want to see one of my actual repos presented by dumbforge, check here.

the following text is LLM generated

Install

npm install --global @superdisk/dumbforge

Git itself must also be installed. The implementation deliberately asks Git to create packfiles instead of reimplementing its storage format.

Configure an R2 remote

An R2 remote has two addresses:

  • the S3 API endpoint, which dumbforge uses to push with your credentials;
  • a public URL, which browsers and ordinary Git use without credentials.

The S3 API endpoint is not the public URL. It normally looks like https://ACCOUNT_ID.r2.cloudflarestorage.com. The public URL is either an r2.dev development URL or a custom domain such as https://git.example.com.

1. Create a bucket and make it public

In the Cloudflare dashboard, open Storage & databases → R2, create a bucket, and open its Settings page. Give it either a Public Development URL or a custom domain. A custom domain is preferable for anything you intend to keep; the r2.dev URL is fine for testing.

You do not need to configure CORS. You should now have these three values:

Bucket:       my-bucket
S3 endpoint:  https://ACCOUNT_ID.r2.cloudflarestorage.com
Public URL:   https://git.example.com

2. Create credentials for dumbforge

From the R2 overview, select Manage R2 API tokens → Create API token. Give the token Object Read & Write access and scope it to the new bucket. When Cloudflare creates it, copy the Access Key ID and Secret Access Key. The secret is only shown once.

These are S3 credentials, not your normal Cloudflare API bearer token. You do not need an AWS account. R2 implements the S3 protocol, and dumbforge directs the S3 client to Cloudflare's endpoint.

The easiest way to save the credentials is with the AWS CLI:

aws configure --profile my-r2

Answer its prompts like this:

AWS Access Key ID:     <the R2 Access Key ID>
AWS Secret Access Key: <the R2 Secret Access Key>
Default region name:   auto
Default output format: <press Enter>

aws configure only writes a standard local credentials file. It does not contact AWS or copy anything there. You can confirm that the profile can reach your bucket before involving Git:

aws s3api list-objects-v2 \
  --profile my-r2 \
  --bucket my-bucket \
  --endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com \
  --max-items 1

An empty bucket may return no objects, which is fine. An AccessDenied error usually means the token was scoped to a different bucket or was not given Object Read & Write access.

If you do not want to install the AWS CLI, export the standard AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION=auto environment variables instead. Omit --profile from the next command in that case, and make sure those variables are present in every shell from which you push.

3. Add the Git remote

Run this inside the local Git repository you want to publish:

dumbforge remote add forge \
  --bucket my-bucket \
  --prefix projects/example.git \
  --endpoint https://ACCOUNT_ID.r2.cloudflarestorage.com \
  --profile my-r2 \
  --public-url https://git.example.com

forge is merely the local name of the Git remote; choose another name if you prefer. Using forge also leaves an existing origin remote alone.

The prefix is where this repository lives inside the bucket. It should normally end in .git. You can host multiple repositories in one bucket by giving each one a different prefix. Pass only the base domain to --public-url; dumbforge appends the prefix itself.

The command configures separate fetch and push URLs:

  • fetch: https://git.example.com/projects/example.git;
  • push: a dumbforge:// URL containing the bucket, endpoint, and profile.

Check them with:

git remote -v

4. Push

Push the repository's current branch. Most new repositories call it main:

git push --set-upstream forge main

If your branch has another name, replace main with the output of git branch --show-current. The first push publishes the complete Git history and builds the initial website. Later pushes upload only new Git objects and use the old and new commits to rebuild changed files and affected shared pages.

Open the repository URL in a browser:

https://git.example.com/projects/example.git

Anyone can clone that same URL with ordinary Git. They do not need dumbforge, an R2 account, or your credentials:

git clone https://git.example.com/projects/example.git

The repository browser is served from that exact URL. Git appends /info/refs; browsers receive the HTML object stored at the repository prefix.

If Git reports that remote-dumbforge is not a Git command, the npm global bin directory is not on your PATH. command -v git-remote-dumbforge should print the installed helper's path before you push.

License

dumbforge is licensed under the GNU Affero General Public License v3.0 only. See LICENSE. Third-party notices and license texts are included in THIRD_PARTY_NOTICES.md.

Development

go test ./...
go build ./cmd/dumbforge