Problem
When you build a lightweight single-page HTML/JS app -- the kind that displays data in a dashboard or feeds content to another app -- you typically need a database and a set of REST API endpoints for CRUD operations. This means designing schemas, writing route handlers, managing migrations, and handling serialization. For simple apps that just need to store and retrieve structured data, this is a lot of infrastructure for very little value. It also makes it harder for AI agents and scripts to interact with your data, since they need to understand your custom API.
Solution
Replace the REST API with a git endpoint served directly from your application server. Store your data as flat files (JSON, CSV, Markdown) in a git repository. Clients and AI agents interact with the data using standard git clone, git pull, and git push commands, authenticated via HTTP basic auth.
Minimal Go server with git HTTP backend:
package main
import (
"log"
"net/http"
"os/exec"
)
func main() {
// Serve the git repository over HTTP with authentication
http.HandleFunc("/data.git/", basicAuth(gitHTTPHandler, "admin", "secret"))
// Serve the single-page app
http.Handle("/", http.FileServer(http.Dir("./static")))
log.Println("Serving on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func gitHTTPHandler(w http.ResponseWriter, r *http.Request) {
cmd := exec.Command("git", "http-backend")
cmd.Env = append(cmd.Environ(),
"GIT_PROJECT_ROOT=/srv/data",
"GIT_HTTP_EXPORT_ALL=1",
"PATH_INFO="+r.URL.Path,
"REMOTE_USER=admin",
"REQUEST_METHOD="+r.Method,
)
cmd.Stdin = r.Body
output, err := cmd.Output()
if err != nil {
http.Error(w, "git error", 500)
return
}
w.Write(output)
}
func basicAuth(next http.HandlerFunc, user, pass string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
u, p, ok := r.BasicAuth()
if !ok || u != user || p != pass {
w.Header().Set("WWW-Authenticate", `Basic realm="data"`)
http.Error(w, "Unauthorized", 401)
return
}
next(w, r)
}
}
Initialize the data repository:
mkdir -p /srv/data/data.git
cd /srv/data/data.git
git init --bare
git config http.receivepack true
AI agents and scripts interact with standard git:
# Clone the data
git clone http://admin:secret@localhost:8080/data.git
# Update data
echo '{"users": 42, "active": true}' > data/stats.json
cd data && git add . && git commit -m "update stats" && git push
The single-page app fetches data from the repo:
// Fetch raw file content directly
const stats = await fetch('/data/stats.json').then(r => r.json());
Why It Works
Git is a content-addressable filesystem with built-in versioning, authentication (HTTP basic auth), conflict resolution (merge), and a universally-understood CLI. Every developer and AI agent already knows how to use it. By exposing a git endpoint instead of a REST API, you eliminate route handlers, serialization logic, and database migrations. You get version history for free, rollback is just git revert, and backups are just git clone. Go servers cross-compile to a single binary for any platform, making deployment trivial.
Context
- This pattern works best for apps with low write frequency -- dashboards, config stores, content feeds, not high-throughput transactional systems
- Go is ideal for the server because it cross-compiles to a single static binary with zero runtime dependencies
- Use HTTP basic auth over HTTPS in production -- never expose git endpoints without authentication
- AI coding agents can natively interact with git, making this pattern particularly useful for agent-driven data pipelines
- For larger datasets, consider git-lfs or keep files under 10MB to avoid repository bloat
- The git history doubles as an audit log of every data change