How I Built this Site
The modern web is bloated. Even simple text blogs are often shipped with megabytes of JavaScript, massive tracking scripts, and heavy database queries running on every single page load.
I wanted to build something different: a beautifully minimal, ultra-fast publishing platform where the final product shipped to the reader is nothing but pure HTML and CSS.
Here is the exact tech stack and architecture I used to build this "Zero-JS" blog from scratch, and host it globally for free.
The Architecture
The core philosophy of this project is decoupling. The database, the backend logic, and the frontend delivery are completely separated.
- Database: Turso (Edge SQLite)
- Backend: C# .NET 9 Minimal API hosted on Render
- Frontend: Astro hosted on Cloudflare Pages
- Security: Single-factor API Key header
- Automation: Cloudflare Webhooks
1. The Edge Database: Turso
Instead of a heavy Postgres instance, I used Turso. It's an edge-hosted SQLite database that replicates globally. It is ridiculously fast and has a generous free tier.
I set up a single Posts table to store the Id, Title, and raw Markdown Content.
2. The Backend: .NET Minimal API
For the backend, I wanted something type-safe, compiled, and lightning-fast. I wrote a C# .NET Minimal API. The entire backend is essentially one single Program.cs file.
It exposes two endpoints:
GET /api/posts: Fetches all posts from Turso.POST /api/posts: Saves a new post to Turso (protected by a customX-API-Keyheader).
I hosted this API on Render. Since the frontend is completely statically generated, this backend only wakes up when I am publishing a new article or when Cloudflare is actively building the site.
3. The Frontend: Astro & Cloudflare
This is where the magic happens. I used Astro, a framework designed for building content-rich websites with zero client-side JavaScript.
At build time, Astro reaches out to my .NET API, downloads all the blog posts, parses the raw Markdown into HTML using the marked library, and bakes everything into static .html files.
Those static files are hosted on Cloudflare Pages, meaning my blog sits on an edge CDN right next to users all over the world. When you click a link, there are no database queries. There is no server rendering. It's just instantly serving a tiny, pre-built text file.
4. The Secret Admin Dashboard
To actually write posts, I built a hidden /admin page right into the Astro site. It features a sleek HTML form where I can type my Markdown content and paste my secret master API key.
Because the API and the frontend are on different domains, I had to explicitly enable CORS (Cross-Origin Resource Sharing) in the .NET backend so my browser wouldn't block the request.
5. The Automation (and The Race Condition)
I wanted the site to update automatically the second I hit "Publish" in my admin dashboard.
To do this, I set up a Cloudflare Deploy Hook. My .NET API is programmed to ping that webhook URL every time a new post is saved to the database, telling Cloudflare to instantly rebuild the site.
The Gotcha: My pipeline was actually too fast.
- .NET saved the post to Turso.
- .NET instantly pinged Cloudflare.
- Cloudflare instantly fetched the posts.
- Turso hadn't finished syncing the new data globally yet, so Cloudflare pulled the old list of posts!
The Fix: I added a simple await Task.Delay(2000); to the .NET API right after the database insert. Giving Turso 2 seconds to breathe completely eliminated the race condition.
The Result
The final product is a custom publishing platform that feels incredibly snappy. The frontend is indestructible, the backend is locked down tight, and the entire stack costs absolutely nothing to run.