May 18, 2026
Our $10/mo SaaS Infrastructure
MockForge Cloud runs on three services and bills under ten dollars a month at launch traffic. Here's the entire stack, why we picked each piece, and the parts we'd change in hindsight.
The stack
Three providers do all the work:
- Cloudflare Pages serves the admin UI (
app.mockforge.dev) and the marketing site (mockforge.dev). Free tier. - Fly.io runs the registry server (
api.mockforge.dev) and every customer's hosted mock (<slug>.mocks.mockforge.dev). ~$3-5/month at our current scale. - Neon hosts the Postgres database. Free tier (0.5 GB storage, scale-to-zero compute) covers us for now.
Plus a few supporting bits: Cloudflare R2 for blob storage (uploaded specs, customer plugins), Stripe for billing, Brevo for transactional email. R2 is free under 10 GB. Stripe and Brevo are free until you have revenue and traffic respectively. Total monthly fixed cost: $0–$2.
Why each piece
Cloudflare Pages for static hosting. The admin UI is a Vite-built React SPA. Cloudflare Pages serves it from their edge, gives us free TLS, free DDoS protection, and a deploy CLI (wrangler pages deploy) that takes 45 seconds end-to-end. Their free tier is generous in a way that's actually meaningful — 500 deploys/month, 100k requests/day on the function layer if we ever need it.
We deploy from a local Makefile target rather than CI to avoid spending hosted-runner minutes on a 45-second job. make deploy-ui, done.
Fly.io for compute. Two reasons. First, the customer-mock workload is "spin up a tiny machine per customer, route by subdomain, auto-stop when idle" — Fly's primitive for this (fly machines, the auto_stop_machines config, the Fly internal-DNS routing) is a near-perfect fit, and no other provider offers an equivalent without significantly more code. Second, the per-region latency is low and the pricing is predictable: shared-cpu-1x:256MB is about $0.15/hour running, free when stopped.
The registry server itself is a single Fly machine in iad (close to Neon's database region) running the Rust binary. The machine spec is shared-cpu-1x:512MB, which is plenty until we have real load.
Neon for Postgres. Two reasons here too. The free tier scales to zero — the database compute shuts off when nothing's hitting it, which is the right shape for a launch-phase product. And the pooled connection endpoint plays nicely with SQLx's runtime-tokio-rustls setup with no special config. The cold-start latency on the first query after idle is ~500ms; for an API server with steady-ish traffic, this is invisible.
What this stack avoids
A few choices we explicitly didn't make:
- AWS. The bill at our launch scale would be similar or higher, the setup time would be 10× longer, and the operational surface area is much wider. EC2 + RDS + CloudFront + Route 53 would work, but the ergonomics for "ship a small SaaS" aren't there.
- Kubernetes. Same logic. We'd be operating clusters before we had customers. The Fly machine primitive does the per-tenant isolation work without a control plane to maintain.
- Vercel. Earlier in the project we did host the marketing site on Vercel, then moved to Cloudflare Pages because the cost trajectory was concerning at scale — generous free tier, then $20/seat/month with a much steeper egress bill than Cloudflare. The migration was an afternoon.
What scales and what doesn't
The bill grows mostly with customer-mock traffic, not registry-server load. At 50 paying customers with mostly-idle mocks, we project ~$40-75/month. The registry server cost stays near-flat until we need multiple instances, which is a Redis-state migration we've scoped but not built yet.
Neon's free tier ends at 0.5 GB storage; their Launch plan starts around $10-15/month, and we can stay there until tens of GB. The pooled-connection endpoint means we can rotate up the connection limit without a code change.
The harder ceiling is operational, not financial. Single-instance registry server is fine until it isn't. Custom-domain TLS provisioning per customer is on the roadmap and will need Cloudflare or Fly TLS automation. These are the kinds of problems that show up at 200-500 paid customers, not 5-50.
Would we change anything
Two things, both small.
We'd put Neon in the same region as the Fly registry app from day one — we had a short stretch where the database was in a different region than the API server and every query took 80ms longer than necessary. Easy fix, embarrassing to miss.
We'd also put more thought into the customer-mock auto-stop tuning earlier. Fly's default idle timeout is generous, which is great for warm performance and bad for the cost-leak we covered in the cost-cap retrospective. Tighter defaults + the per-deployment rate limit get us closer to "pays for itself per customer" math.
Otherwise the stack does what it should: cheap when nobody's using it, scales linearly with customer traffic, doesn't require us to operate anything we shouldn't be operating at this stage.