Skip to main content

Why I ditched traditional CMS platforms for a custom-built stack

Stefan Cosma Stefan Cosma · April 28, 2026 · Updated May 21, 2026 · 3 min read
Cover image — Why I ditched traditional CMS platforms for a custom-built stack

Just as the title implies, this post covers what it takes to move away from rigid, off-the-shelf CMS solutions in favor of a bespoke architecture. I wanted a setup that combined the speed of a static site with the power of a modern cloud infrastructure. To do this, I landed on a stack featuring Astro, Vercel, Cloudflare, and Supabase, with Resend handling the communication layer.

The Frontend: Performance-First with Astro

The core of the site is built on Astro, which I chose for its "zero-JS by default" footprint. While many modern frameworks ship megabytes of JavaScript for a simple blog, Astro lets me keep the frontend lean.

However, I didn't want a purely static site that requires a full rebuild every time I fix a typo. I’m utilizing Astro SSR (Server-Side Rendering) to fetch content dynamically. This gives me the best of both worlds: the SEO benefits of a static site with the real-time flexibility of a database-backed application. Everything is built using TypeScript and React, styled with Tailwind CSS, and kept clean using Biome for linting and formatting.

The Infrastructure: Cloudflare & Vercel

For the plumbing, I’m pushing my code to GitHub, which triggers an automatic deployment to Vercel. Vercel handles the SSR logic and global distribution perfectly, but I've also layered Cloudflare on top.

Cloudflare acts as the primary gateway, handling DNS and providing an extra layer of caching and security. By having Cloudflare sit in front of Vercel, I have granular control over how traffic hits the site and an added layer of protection against the usual web noise.

The Content Engine: Custom CMS & Supabase

To manage the blog, I built a Custom CMS with its own admin interface. Instead of being locked into a specific CMS provider's UI or API, I handle the full CRUD lifecycle myself.

The CMS communicates with Supabase, which acts as my database and authentication provider. When I save a post, the data is stored in my tables and instantly becomes available for the Astro frontend to fetch via SSR. It’s a seamless flow that keeps me in total control of my data schema.

Automating the Newsletter with Edge Functions

The part of this project I’m most excited about is the automated notification system. I wanted a way to notify subscribers the second a new post goes live without any manual intervention.

The logic follows a clean, event-driven pipeline:

  • Trigger: A new row is inserted into the posts table.
  • Webhook: Supabase detects the change and triggers a webhook.
  • Process: The webhook calls a Supabase Edge Function.
  • Broadcast: The function hits the Resend API, which sends a templated email to my "General Segment" of subscribers.

Final Thoughts

This rebuild wasn't just about changing where my text is stored; it was about building a cohesive system where the frontend, backend, and delivery layers work in sync. I applied the same logic to my contact page, using Resend with Audience Segments to ensure messages are categorized and formatted before they even hit my inbox.

This setup gives me total control over my content pipeline while keeping the user experience fast and accessible. If you're looking to move beyond a basic WordPress or Ghost setup, building your own stack is a challenge worth taking.

If you have any ideas on how to further optimize this infrastructure, let me know. You can reach me on most social media channels!

Mastodon