Running a SaaS on 18MB: How Forecastly's Backend Works
Forecastly is a cash-flow forecasting app I built for freelancers and small businesses. It has a web app, an iOS app, subscription billing, and bank syncing.
The entire backend is a single compiled binary. Under 18MB. It runs on a cheap VPS. The database is a managed free tier. Here’s how that works and where it breaks.
The architecture
The backend is a Go HTTP server that compiles to a single static binary with no runtime dependencies on the host. Deployment is: build in CI, upload the binary, restart the service. That’s the whole pipeline.
┌─────────────────┐ ┌─────────────────────────────┐
│ Web App │────▶│ │
│ (CDN) │ │ Go API │
└─────────────────┘ │ ├── Auth │
│ ├── Billing │
┌─────────────────┐ │ ├── App data │
│ iOS App │────▶│ ├── Payment webhooks │
│ (StoreKit 2) │ │ ├── Bank sync │
└─────────────────┘ │ └── Background jobs │
│ │
┌─────────────────┐ └──────────┬──────────────────┘
│ Payment │────▶ │
│ providers │ ┌──────────▼──────────────────┐
└─────────────────┘ │ Managed database │
└─────────────────────────────┘
One binary serves everything: authentication, payment processing, subscription management, bank transaction syncing, and background jobs.
Why not serverless
The earlier version ran on serverless functions across two cloud providers. I migrated away from it.
Serverless cold starts on a cash-flow app — where you open it and expect your balance immediately — felt bad. Database connection pooling in a serverless context is a known pain point: every cold start can open a new connection, and managed free tiers have connection limits you can hit faster than expected with concurrent invocations.
But the real reason: a cheap VPS running a compiled binary is less infrastructure to manage than function packaging across multiple providers. For a solo developer, reducing operational surface area matters more than theoretical scalability.
What it costs
Monthly infrastructure:
| Service | Cost |
|---|---|
| VPS | single digits |
| Managed database (free tier) | $0 |
| CDN (web frontend) | $0 |
| Domain | ~$1 (amortized) |
| Total | under $10/month |
Payment processors take their standard percentage per transaction, and Apple takes 30% of App Store subscriptions. But that’s per-revenue, not infrastructure. The fixed cost of running the backend is trivial.
Deployment and the iOS side
CI/CD handles builds and deploys. The pipeline builds the binary, uploads it, swaps it in place, restarts the service, and runs a health check. Under 60 seconds end to end.
The iOS app talks to the same API over HTTPS with token-based auth via Sign in with Apple. For App Store billing, the app completes a StoreKit 2 purchase, confirms it with the backend, and the backend verifies it with Apple. Renewals, expirations, and refunds arrive asynchronously via server notifications.
What’s fragile
The honest answer about running production on a minimal setup:
Single point of failure. There’s no load balancer, no failover. Uptime has been fine, but this setup has no redundancy. For an indie app, that’s an acceptable tradeoff. For anything with an SLA, it’s not.
Database free tier limits. Shared cluster with limited storage. I’m nowhere near the limits, but shared clusters can have latency spikes. Scaling past the free tier is a steep price jump for an indie project.
In-process background jobs. Background syncs run inside the API process. If it crashes mid-sync, it retries on the next cycle. No external scheduler, no retry queue. Reliable enough so far.
Is this a real architecture?
It depends on your definition. This isn’t microservices. It’s not Kubernetes. It’s a single compiled binary on a single VM talking to a managed database.
But it handles real money — payments, subscriptions, bank transactions. It has auth, encryption, webhooks, and background jobs. And it all fits under 18MB and costs less than a coffee per month to run.
For indie SaaS, the question isn’t whether it scales. The question is whether it works reliably at the scale you’re actually at. For Forecastly, it does.