Skip to content
Cloud

Why I'm hosting personal projects on Cloudflare Workers in 2026

Workers, D1, R2, Turnstile, Tunnel and Access: a tour of the Cloudflare stack behind this site and my homelab, and why the monthly bill rounds to zero.

Daniel HallSolutions Architect
6 min read

Last year I rebuilt this site from the ground up on Next.js, Sanity for the writing section, a growing list of browser-based developer tools, and a contact form. When it came to deciding where it would all be hosted, there wasn't much of a decision to make. It went onto Cloudflare Workers, because everything I've built for myself over the past couple of years has ended up on Cloudflare Workers, and I want to tell you why.

Fair warning: I'm going to talk about money a bit in this post. The money is most of the point.

For context, a good chunk of my career has been spent designing systems on Azure, so this isn't a case of not knowing what the big clouds offer. Actually, it's closer to the opposite. Azure, AWS and GCP have fantastic offerings for small-scale apps. Azure Container Apps are great for hosting .NET API-first back-ends, and can be very cheap. When it comes to hosting JavaScript apps that don't get loads of traffic, however, the benefits of Cloudflare really shine.

The hosting

This site is a Next.js app compiled for Workers by OpenNext. The build takes standard Next output and produces a single Worker that serves the pages, API routes and static assets from Cloudflare's edge.

The free plan gives you 100,000 requests a day, with up to 10 milliseconds of CPU time per invocation. That CPU figure sounds absurd until you learn it measures actual compute rather than wall-clock time. The hundreds of milliseconds a request spends waiting on a CMS or a database don't count. A server-rendered page on this site fits inside the budget with room to spare. If you outgrow it, the paid plan is $5 a month with 10 million requests and 30 million CPU milliseconds included.

On the free plan, worker bundles are capped at 3 MiB, and I met that limit the hard way when Sanity Studio tried to bring its 15 MiB of JavaScript along for the ride. Studio now lives on Sanity's own hosting rather than inside this app, which, in hindsight, is where it should have been all along. Good constraints do that 😉

The storage

Two pieces here: useful free tier, then prices that remain low for most personal projects.

D1 is Cloudflare's SQLite database. Provisioning it is literally a single wrangler command and a binding in your config. The free tier covers 5 million row reads and 100,000 row writes a day, with 5 GB of storage, and Time Travel gives you point-in-time restore on top. On the paid plan the included numbers jump to 25 billion reads and 50 million writes a month. I generally use Supabase for Postgres and Auth, and plan to discuss Supabase vs Neon vs others in a separate post.

R2 is the object store. It's an S3-compatible API, 10 GB free, then $0.015 per GB-month. There are no egress fees. I use R2 personally and professionally mostly for caching. OpenNext can use an R2 bucket as the incremental cache for a Next.js deployment, so rendered pages persist across the fleet instead of being rebuilt per isolate.

The front door

The contact form on this site is protected by Turnstile, Cloudflare's CAPTCHA replacement. It's free for up to 20 widgets, and in managed mode most humans never see a challenge (no traffic-light photographs 🙂).

Because my DNS runs through Cloudflare too, the whole site sits behind their proxy. DDoS protection is on by default, and the free plan includes enough WAF to write custom rules against the obvious nuisance traffic (there is always nuisance traffic. Check your logs sometime). Cloudflare is the firewall for everything I run at the moment, personally and mostly professionally. That includes the hardware in my office at home, which brings me to the fun part.

The homelab

I run a home server: Immich for photos, a NAS for backups, and countless other apps. The traditional way to reach these from outside the house is port forwarding… and a prayer… and hoping it's secure.

Cloudflare Tunnel takes the ports out of the equation. A small daemon called cloudflared runs on the server and makes an outbound connection to Cloudflare's network, and your services become hostnames on your own domain with zero inbound ports open on the router. From the internet's side there is nothing to scan. Tunnels are free, with no bandwidth caps.

By the way, I also use Tailscale as a VPN to connect directly to my home servers remotely. I highly recommend it if you haven't used it.

So, with Cloudflare Tunnels, now your Immich login page is on the public internet. This is where Cloudflare Access earns its place. Access puts an SSO wall in front of any hostname. I authenticate once with my Google account and every internal tool behind it opens like it's on the LAN. The Zero Trust free plan covers 50 users, and so I also use it to gate my UAT/staging environments for small projects I build for other people, and internal projects, professionally.

An Access policy in front of a staging hostname takes literally ten minutes to set up, costs nothing, and means the URL is useless to anyone who isn't on the list.

The AI bits

Cloudflare also has a complete stack here. Workers AI runs open models (Llama, Mistral, Whisper and… friends) on Cloudflare's GPUs, billed per use like everything else on the platform. AI Gateway is a proxy you put in front of any LLM provider to get caching, rate limiting, retries, fallbacks and analytics without touching application code. Vectorize covers the vector database side for RAG work, and the Agents SDK gives long-running agents somewhere durable to live.

The bill

Totting it all up for a typical personal project:

  • Workers hosting: free, or $5 a month once you outgrow the free plan.
  • D1 database: free. 5 GB of SQLite with point-in-time restore.
  • R2 storage and caching: free to a few pennies. No egress fees, ever.
  • Turnstile: free.
  • Tunnel and Access: free at personal and household scale.
  • DNS, DDoS protection, basic WAF: free with the domain on Cloudflare.

The equivalent AWS setup (a small EC2 instance or two, RDS, a load balancer, a NAT gateway) can land somewhere between £40 and £100 a month.

Professionally, we've chosen to migrate all internal JavaScript-based apps and small public-facing apps out of Azure and into Cloudflare. The Observability and Analytics tools on Workers are somewhere between sufficient and good. The Security Analytics on the Firewall are very easy to use and navigate, and overall the bill is hugely reduced.

The catch

Of course, this is a lot of eggs in one basket. Cloudflare is my registrar, DNS, CDN, compute, database, object store and auth layer. When they have a bad day (and they've had a few recently), I don't have a failover plan. I have a wait.

The lock-in isn't bad, mind you. D1 is SQLite underneath, and an export is just a file. R2 speaks the S3 API, so leaving that is a copy job. The stickiest part is the Worker runtime itself, with its bindings and its not-quite-Node environment, though OpenNext keeps the application layer portable enough that the rework would be measured in days rather than months. It didn't take long to migrate some apps out of Docker, Azure Container Apps, into Cloudflare, and it won't take long to move them back out.

For my personal projects, the whole estate (this site, the tools on it, the tunnels into the homelab) costs less per month than a coffee. If that ever changes you'll get a follow-up post, but my money is on the coffee inflating first.

Further reading

Related posts