Why I moved Flow's AI off Firebase mid-build
I want to tell you about a decision I made three weeks into building Flow’s backend that cost me a week of re-architecture. Not because I’m proud of it, but because I don’t see enough solo founders writing about the part where you change your mind about infrastructure mid-build.
The short version: Flow’s AI features moved off Firebase Functions onto Cloudflare Workers. Here’s what actually happened.
What I had
The original design was Firebase all the way. Firebase Auth, Firestore for session data, Firebase Functions for everything callable from the Android app. That included the two AI features that matter most to Flow: the daily focus plan (which calls Claude to generate 2 to 3 realistic deep work blocks based on your calendar and HRV) and the now-reset coach (a short, mid-session nudge that reads your current cognitive state and tells you whether to keep going or step away).
Firebase works well for a lot of this. Auth is genuinely good. Firestore’s real-time sync is exactly what a focus session timer needs. I wasn’t looking for a reason to change anything.
The friction point
Firebase’s free tier (the Spark plan) doesn’t allow outbound network calls to external services. That means no calling Anthropic’s API from a Firebase Function without upgrading to Blaze (pay-as-you-go). Blaze itself isn’t expensive at low volume, but it’s a billing relationship I wasn’t ready to enter during pre-launch, when I have zero paying users and an unpredictable call pattern.
I spent a few hours looking at whether I could route through a proxy, or stage the Anthropic call differently. Everything I found was either fragile or defeated the point of using Firebase Functions in the first place.
The decision wasn’t really about cost. The Blaze costs at my scale would’ve been trivial. It was about what happens when you’re the only engineer and you have a billing account on a pay-as-you-go service with a usage pattern you don’t yet understand. I didn’t want a runaway Cloud Function bill at 2am because I forgot to set a spending cap.
Why Cloudflare Workers
I’d been watching Cloudflare Workers for a while. The economics are different: the free tier includes 100,000 requests per day with no outbound network restriction. You can call Anthropic directly. The runtime is V8-based, cold start time is essentially zero, and the deployment pipeline with Wrangler is fast.
More importantly for Flow’s now-reset coach: Workers support streaming responses natively. When a user is mid-session and asks the coach whether to keep going, I don’t want them staring at a spinner for three seconds. Server-sent events from a Worker stream the Claude response token by token. That’s a qualitatively better experience, and Firebase Functions (especially on a cold start) weren’t the right tool for it.
What the split looks like now
The architecture is now a hybrid. Firebase handles everything it was already good at: Auth, Firestore, push notifications, and four of the six callable functions (session lifecycle, HRV data ingestion, user preferences, journal entries). None of those need external API calls.
The two AI callables (the focus plan generator and the now-reset coach) live at api.flowdeep.app as Cloudflare Workers. The Android app calls them directly via HTTPS, with a Firebase Auth token in the Authorization header that the Worker verifies before touching anything.
The Workers are thin. They receive the request, validate the token, call Anthropic’s API with a structured prompt, and stream the response back. No state lives in the Worker. All persistence goes back to Firestore via the Firebase Admin SDK.
What it actually cost
One week. That’s what changing your mind about infrastructure mid-build costs when you’re one person.
The Wrangler setup, the Worker code, the streaming implementation, the token verification flow: individually, none of it was hard. The cost was context switching. I had a mental model of how the app worked that assumed Firebase end-to-end. Pulling two services out of that model and re-routing them through a different runtime required holding more in my head than I wanted during a period when I should’ve been building user-facing features.
If I were starting over, I’d have used Cloudflare Workers for the AI callables from day one. The Spark limitation on outbound calls isn’t a secret. It’s in Firebase’s pricing documentation. I should’ve noticed it earlier.
Is the hybrid awkward?
Less than I expected. The Android app doesn’t know or care whether it’s talking to Firebase or Cloudflare. It’s calling HTTPS endpoints either way. The Firebase Auth token is the trust anchor in both paths. The Firestore schema didn’t change.
The operational overhead is one additional deployment target. I run wrangler deploy in the Workers directory and firebase deploy --only functions for the rest. Both pipelines are fast.
The one thing I’d still like to solve is unified observability. Right now, Firebase’s built-in logging and Cloudflare’s Workers logs are separate. For the volume I’m running, that’s a minor inconvenience. When I have actual users, I’ll want a single log aggregator.
Where this leaves Flow
Both AI features are working in testing. The focus plan generates in under two seconds. The now-reset coach streams. I’m testing both daily on my own device.
The practical lesson isn’t that Firebase is wrong or that Cloudflare Workers is obviously right. It’s that the Spark-to-Blaze upgrade decision isn’t purely about money. It’s also about risk tolerance during pre-launch. If your risk tolerance differs from mine, Firebase Functions + Blaze is a completely reasonable choice.
If you’re building something similar and want to talk through the architecture, I’m on X at @useflowdeep. And if you want to follow what comes next, the waitlist at flowdeep.app is the right place to be.
Sandi
Join the conversation