<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax" -->

---
title: what if my git host were a static site generator?
description: A developer introduces sorcery, a git repo viewer built like a static site generator rather than a full git forge. It rebuilds static HTML overview pages,...
canonical: https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: what if my git host were a static site generator? | daily.dev
og:description: A developer introduces sorcery, a git repo viewer built like a static site generator rather than a full git forge. It rebuilds static HTML overview pages,...
og:url: https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax
og:image: https://api.daily.dev/og/posts/eYCXgaJax.png
og:image:alt: what if my git host were a static site generator?
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# what if my git host were a static site generator?

**[Lobsters](https://daily.dev/sources/lobsters)** · 6 min read · 0 upvotes · 0 comments

## Summary

A developer introduces sorcery, a git repo viewer built like a static site generator rather than a full git forge. It rebuilds static HTML overview pages, trees, and syntax-highlighted source on push, while serving the raw .git directory alongside a client-side JavaScript git client for historical browsing, avoiding scraper-hostile solutions like Anubis. It intentionally omits accounts, issues, PRs, and wikis, staying read-only while writes happen over git-over-ssh with a separate ForceCommand tool called sorcery-ssh. The design optimizes for read-heavy workloads on tiny personal servers, using techniques like a custom binary git object bundle endpoint to avoid multi-hundred-megabyte packfile fetches.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://char.lt/blog/2026/09/sorcery-repo-viewer>

## Questions this post answers

### How can I serve a git repo viewer without running into scraper load problems on a small server?

Build the repo viewer as a static site generator: on each push, rebuild fixed HTML pages (overview, tree, syntax-highlighted source for branch tips) so serving becomes a cheap sendfile-and-forget operation rather than dynamic computation per request. This avoids resource exhaustion under scraper load without needing a JavaScript proof-of-work gate like Anubis, since reads vastly outnumber writes in typical git browsing workloads.

_daily.dev surfaces build-vs-buy tradeoffs like this for developers weighing self-hosted infrastructure options._

### Why is directly fetching git packfiles over a network so slow for viewing repo history?

Git stores objects compressed in delta-encoded packfiles, so naively fetching a packfile index just to view one commit's diff in a large repo like linux.git can require over 400MiB of bandwidth. Smart range-scanning avoids that but kills cache hit rates and creates request waterfalls, since later fetches depend on data from earlier ones, making history browsing feel slow on high-latency connections.

_developers debugging git protocol performance can track write-ups like this on daily.dev._

### What is the difference between a git forge and a git repo viewer?

A git repo viewer, unlike a full git forge such as Forgejo or GitLab, omits user accounts, SSH/GPG key management, issues, and pull requests, staying entirely read-only for browsing code. Writes happen separately through git-over-ssh with a ForceCommand tool that autocreates repos on first push, keeping the public-facing viewer's attack surface limited to whatever serves static files and sshd.

_daily.dev helps developers weighing forge features against lightweight repo-browsing setups compare real-world tradeoffs._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 16 comments across lobsters, hackernews (as of 2026-09-13).

**TL;DR:** The write-up drew an enthusiastic reception from people who appreciate a lightweight, static alternative to full git forges, with lots of prior-art comparisons and technical nitpicking about caching and the client-side git approach.

**Sentiment:** 55% positive · 35% mixed · 10% skeptical

**The case for**

- Several people found it visually polished and fast, even on mobile.
- It's seen as a timely, practical answer to LLM/scraper traffic hammering self-hosted git forges like Gitea.
- The SPA-based approach to deterring scrapers is seen as a clever alternative to proof-of-work tools like Anubis, since it forces multiple rate-limitable requests.
- The author's incremental build approach that reuses unchanged highlighted file views was noted as a sensible design choice.

**The pushback**

- Some questioned why the eager rebuild-on-push approach was chosen over lazy/on-demand HTML generation (akin to ISR), noting that pattern is complicated in practice.
- Concerns were raised that an in-browser git client over a dumb protocol could be slow due to high-latency round trips and could increase server load compared to smart-protocol clients.
- Whether this actually helps against bots depends on how closely scrapers emulate full browser sessions, and the anti-bot arms race is pushing them in that direction anyway.
- One commenter was put off by the tech stack, particularly the amount of TypeScript, for a project they assumed was mostly Rust.

**By community**

- lobsters (positive): Warm reception with detailed technical feedback, comparisons to similar tools, and a few caveats about performance and stack choices.
- hackernews (mixed): No comment content was provided, so little can be said about the discussion there.

**Hottest debate:** Whether eager static rebuilding on push is better than lazy/on-demand generation with caching.

**Open questions**

- Would lazy generation with cache invalidation on repo update be a simpler or more efficient approach than eager rebuilding?
- How effective is the client-side SPA approach actually at deterring scrapers versus more sophisticated bots that emulate full browsers?

**Highlights**

> The classic implementation of this idea is [stagit](https://codemadness.org/stagit.html) or perhaps it’s more like [browsegit](https://github.com/namazso/browsegit) [Annoyingly, “static web site” used to mean “no dynamic HTML templating” but now it sometimes means “no server-side HTML templating but lots of client-side HTML templating”.] I would expect an in-browser git client to be really slow since it requires lots of back-and-forth chatting over a high-latency link. And I would expect a dumb-protocol client to make the server load worse since it doesn’t have the smart-protocol optimizations. Whether this is a win against bots or not depends on how much the bots are emulating a full-fat browser session; unfortunately the arms race against things like Anubis is pushing the bots in that direction.
> — [fanf on lobsters · 6 points, 1 comments](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site#c_vgd0ic)

> > when it receives an update to a git repo, it will rebuild a bunch of on-disk HTML for that. … this allows us to pay a fixed upfront cost for serving many future requests Alternatively it could generate the HTML lazily: generating each file when it’s requested but  missing, and clearing the entire cache directory whenever the repo updates.
> — [snej on lobsters · 3 points, 2 comments](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site#c_sx8dvi)

> Serving an SPA instead of Anubis feels like the better way of forcing the client to do some proof of work! Moreover if you need the SPA to navigate, it forces the client to make multiple requests, which can be rate-limited if needed (I don't think the residential proxies share a browser).
> — [oliverpool on lobsters · 1 points](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site#c_a1t8pv)

> It looks really nice, and it *feels* nice even on my phone (btw, unlike GH). I'm not completely sure what is this build on. Looks like it could be rust, but there's a 29% of ts that kind of puts me off. May make sense, that the fronted is written in ts, and I'm probably silly... but I don't want to touch that stack in my personal projects.
> — [reidrac on lobsters · 2 points](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site#c_fyltw3)

> author here!! the reason i _didn't_ do this is because the initial design was daemonless (it was just a generator that ran on git post-receive + nginx for serving), and i still want to support that mode of operation: consider a thing that builds your git repo view & then uploads it to a static CDN! the generator does do incremental builds, and it will reuse unchanged highlighted file views from a previous commit
> — [char on lobsters · 2 points](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site#c_zmpwz4)

**Source threads**

- [lobsters](https://lobste.rs/s/6syfar/what_if_my_git_host_were_static_site) · 30 points · 16 comments
- [hackernews](https://news.ycombinator.com/item?id=49684910) · 4 points · 0 comments

## Similar posts on daily.dev

- [You already have a git server: \(Maurycy's blog\)](https://daily.dev/posts/you-already-have-a-git-server-maurycy-s-blog--z2gsbe3ok) · Hacker News · 3 upvotes · 0 comments
- [What alternatives exist for Anonymous Github?](https://daily.dev/posts/what-alternatives-exist-for-anonymous-github--x4ersrjfw) · Lobsters · 0 upvotes · 0 comments
- [Introducing gisthost.github.io](https://daily.dev/posts/introducing-gisthost-github-io-bfmys81py) · Simon Willison · 169 upvotes · 2 comments
- [antonmedv/gitmal: A static page generator for repos](https://daily.dev/posts/antonmedv-gitmal-a-static-page-generator-for-repos-qzbjs2xm0) · Lobsters · 0 upvotes · 0 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#git](https://daily.dev/tags/git), [#self-hosting](https://daily.dev/tags/self-hosting), [#forgejo](https://daily.dev/tags/forgejo)

[View this post on daily.dev](https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"what if my git host were a static site generator?","url":"https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax"},"datePublished":"2026-09-13T20:05:28.466Z","dateModified":"2026-09-13T23:06:14.043Z","description":"A developer introduces sorcery, a git repo viewer built like a static site generator rather than a full git forge. It rebuilds static HTML overview pages,...","image":"https://media.daily.dev/image/upload/s--CxzD6vbw--/f_auto/v1722860399/public/Placeholder%2005","thumbnailUrl":"https://media.daily.dev/image/upload/s--CxzD6vbw--/f_auto/v1722860399/public/Placeholder%2005","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"javascript,git,self-hosting,forgejo","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"what if my git host were a static site generator?"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/what-if-my-git-host-were-a-static-site-generator--eycxgajax#faq","mainEntity":[{"@type":"Question","name":"How can I serve a git repo viewer without running into scraper load problems on a small server?","acceptedAnswer":{"@type":"Answer","text":"Build the repo viewer as a static site generator: on each push, rebuild fixed HTML pages (overview, tree, syntax-highlighted source for branch tips) so serving becomes a cheap sendfile-and-forget operation rather than dynamic computation per request. This avoids resource exhaustion under scraper load without needing a JavaScript proof-of-work gate like Anubis, since reads vastly outnumber writes in typical git browsing workloads. daily.dev surfaces build-vs-buy tradeoffs like this for developers weighing self-hosted infrastructure options."}},{"@type":"Question","name":"Why is directly fetching git packfiles over a network so slow for viewing repo history?","acceptedAnswer":{"@type":"Answer","text":"Git stores objects compressed in delta-encoded packfiles, so naively fetching a packfile index just to view one commit's diff in a large repo like linux.git can require over 400MiB of bandwidth. Smart range-scanning avoids that but kills cache hit rates and creates request waterfalls, since later fetches depend on data from earlier ones, making history browsing feel slow on high-latency connections. developers debugging git protocol performance can track write-ups like this on daily.dev."}},{"@type":"Question","name":"What is the difference between a git forge and a git repo viewer?","acceptedAnswer":{"@type":"Answer","text":"A git repo viewer, unlike a full git forge such as Forgejo or GitLab, omits user accounts, SSH/GPG key management, issues, and pull requests, staying entirely read-only for browsing code. Writes happen separately through git-over-ssh with a ForceCommand tool that autocreates repos on first push, keeping the public-facing viewer's attack surface limited to whatever serves static files and sshd. daily.dev helps developers weighing forge features against lightweight repo-browsing setups compare real-world tradeoffs."}}]}
```

