# Why Go, Postgres and Django

31 October 2026

![A cog looming like a sun in a warm haze of fine rays, over a pine forest](https://fiveb.ar/img/blog/why-go-postgres-and-django.svg?v=85e8b3f3)

fivebar is built from three well-worn tools. [Go](https://go.dev) runs the servers near your visitors, [Postgres](https://www.postgresql.org) keeps the counts, and [Django](https://www.djangoproject.com) draws the pages, the API and our MCP server. None of them is new, which is much of why we chose them.

fivebar’s first version ran on a large American cloud platform. It was quick to build on and very good at what it does. In October we rewrote fivebar to run on servers of our own, so that nothing we keep about you or your visitors rests in the USA or with a US company. That meant choosing a language and a database again, for each part.

## Three parts

Children are servers in cities around the world, near you and your visitors. We add more as fivebar’s customer base grows.

Mother, in Germany, counts the visits. Home, beside her, is everything you and your apps talk to.

A visitor to your site, and you or your AI assistant, each reach the nearest of fivebar’s children, servers in cities around the world, written in Go, with more cities to come. The children send page views, without IP addresses, to mother, in Go, and every other request to home, in Django, both in the core in Germany. Mother writes the counts to Postgres, and home reads them.

How a visit reaches fivebar. The children answer for the tracker and take page views. Everything else goes on to the core in Germany.

## Go, at the edge

A child is one program, written in Go. It’s [Caddy](https://caddyserver.com), an open-source web server, with a module of our own built in. Caddy looks after the certificates and connections. Our module serves the tracking script, checks each page view, swaps the visitor’s IP address for an anonymous code, which changes every day and can’t be turned back into the address, and sends the page view on to Germany. Every other request is passed back home.

Go builds all of that into a single file with nothing else to install. So a new child is a small server, at whichever company has one near your visitors, with that file copied onto it.

Children keep nothing on disk. Every site’s settings, the day’s secret that makes visitor codes and the page views waiting to be sent are all held in memory, compressed to about 45 bytes a page view. Switch a child off and what it held goes with it. This is what lets us run children with companies outside the EU and still promise that nothing rests there. If a child can’t reach Germany, it keeps counting and holds on to what it counted.

Mother is Go too. She’s one program that stays running, keeps the visits still going on in memory and writes the totals about once a minute. With both in Go, a page view travels from a child to the database through one language, in a format written once and shared by both.

## Postgres, for the counts

We tried some cleverer options first. A data lake took between half a second and four and a half seconds to answer a query, which is far too slow for a dashboard. Databases that charge for each row written got expensive at exactly the moment a site does well.

We keep counts, not a log of every page view. Each row is a day’s count of one combination of page, source, country and so on. A visitor’s code never reaches Postgres. Mother keeps those in a small database of her own for 30 hours, and then they’re gone.

One small piece of denormalisation keeps the dashboard quick. Beside the full counts, Postgres keeps a row of totals for each site and day, updated in the same write. So a chart or a list of sites reads one row a day for each site, rather than every combination, and answers 30 to 40 times faster.

## Django, for everything you see

Home is everything a person or an app reads or changes: the dashboard, settings, billing, the docs, this blog, the API and our MCP server. It’s one Django app, in Python.

Django has been around for twenty years and is good at exactly this. It draws pages on the server, so they arrive ready to read, and it comes with forms, templates and excellent [database migrations](https://docs.djangoproject.com/en/stable/topics/migrations/) we would otherwise have built ourselves.

Python is also where the AI tools are. Our [MCP server](https://fiveb.ar/docs/mcp.md), which lets Claude, ChatGPT and others read your stats, is built on the [official MCP library for Python](https://github.com/modelcontextprotocol/python-sdk). It sits beside the dashboard and the API and uses the same queries, so a figure reads the same wherever you ask for it.

Counting stays out of Django. Its many short-lived workers can’t keep visits in memory the way mother does.

## The trade-offs

Two languages is perhaps one more than we’d like, and a change to what the children send means updating them and mother in turn. We also look after our own servers now, with their keys and updates, where a platform did that for us before. We think it’s worth it to be able to say [exactly where your data is](https://fiveb.ar/docs/infrastructure.md).
