Loading Breadcrumbs...

How This Site Is Built

How This Site Is Built (and Why It's Decoupled)

Most small-business sites are one thing: a WordPress install, or a site builder, with the frontend and backend fused together. This one isn't, and the split is deliberate. Here's the architecture and the reasoning — because the reasoning is the interesting part.

Two halves, talking over an API. The frontend — what you're reading right now — is a Svelte app. The backend is Django. They're separate applications. The frontend doesn't know how the database works; it asks the backend for data over an API and renders it. The backend doesn't know or care what the frontend looks like; it serves data and enforces the rules. That's what "decoupled" means: each side can change, break, or be rebuilt without dragging the other down.

Why bother splitting them?

  • The right tool for each job. Svelte is excellent at fast, interactive interfaces. Django is excellent at data, auth, and an admin panel I get almost for free. Coupling them would mean compromising one to satisfy the other.
  • The backend outlives the frontend. If I ever rebuild the frontend in something new, the Django API and all its data stay put. The same backend could feed a website, a mobile app, and a point-of-sale system at once — which is exactly what I needed for Cabalito.
  • A clear security boundary. The public only ever talks to the frontend and a defined API surface. The database sits behind Django, off the public internet entirely.

Server-side rendering, so it's not a blank page. Decoupled frontends have a classic weakness: the browser loads an empty shell, then fetches the data, so the first thing a visitor — or a search engine — sees is nothing. I render these pages on the server instead. By the time the page reaches your browser, the content (this post included) is already in the HTML: fast to first paint, fully visible to crawlers, and still hydrating into a snappy Svelte app once it loads. The SEO and speed of a static site with the flexibility of a dynamic one.

Held together by Nginx and Docker. Each piece runs in its own Docker container — Svelte, Django, Nginx — with Nginx out front as the traffic cop, routing page requests to the frontend and API calls to Django. Postgres handles the data, Cloudinary handles the images. Every part is replaceable on its own.

That's the whole philosophy: small, independent pieces that each do one thing well, wired together cleanly. It's more work than clicking "install WordPress." It's also why this site is fast, secure, and built to grow instead of needing a rebuild.