A startup client came to us needing a working product to show early users within a few weeks, with no dedicated backend engineer on their side and a budget that could not stretch to building and hosting a full custom backend just to validate the idea. We built the MVP almost entirely on Firebase.
What Firebase covered out of the box
- Firebase Authentication handled email, Google, and Apple sign-in out of the box, removing what is usually a week or more of careful, security-sensitive work on its own
- Firestore's real-time listeners meant the app's core collaborative feature — multiple users seeing each other's updates live — came essentially for free, without us writing any websocket or polling code ourselves
- Firebase Hosting and Cloud Functions rounded out the few places that needed genuine custom server-side logic, like sending a welcome email on signup
Why three weeks was actually realistic here
A three-week MVP timeline sounds aggressive for anything with real user accounts and live collaborative data, and it would have been unrealistic if we had needed to build authentication, a real-time sync layer, and hosting infrastructure ourselves from scratch. What made it realistic was that all three of those pieces are exactly what Firebase is built to provide as a managed service, which let the team spend nearly all three weeks on the product's actual distinguishing feature rather than on infrastructure that, for this specific idea, was not where the client's competitive advantage was going to come from anyway.
Why we did not instead reach for a fast Node-plus-Postgres starter kit
We seriously considered a more traditional but still fast-to-stand-up option — a Node API backed by Postgres, using one of our existing internal starter templates — before settling on Firebase, since it is the stack most of the team has the deepest experience with. What tipped the decision toward Firebase specifically was the real-time collaborative feature at the product's core, which a traditional REST API would have needed either polling or a custom websocket layer to support, both of which would have consumed a meaningful chunk of the three-week timeline that Firestore's built-in real-time listeners gave us for free. For an MVP without that specific real-time requirement, our own Node-and-Postgres starter would likely still have been the faster and more familiar path.
A security rule mistake that could have been serious
Firestore's security rules, which control who can read and write which documents, are declarative and live outside application code entirely, which is powerful but also means a rule mistake fails differently than an application-code bug would. Early in the build, an overly permissive rule intended to let any authenticated user read their own profile document accidentally allowed any authenticated user to read any user's profile document, due to a missing document-ID match condition in the rule itself. We caught this during a pre-launch security review rather than after launch, but it is exactly the kind of mistake we now specifically test for on every Firebase project, since a rules bug like this one produces no error anywhere in application code — the app simply works, quietly returning more data than it should to a client that would in a traditional backend never have been granted that access in the first place.
Data modeling considerations Firestore's document model forced early
Firestore's document-and-collection model does not support the same kind of relational joins a SQL database would, which meant thinking harder about data modeling upfront than the team might have for an equivalent Postgres-backed MVP. A feature showing "which of your friends also joined this week" required denormalizing some friend-relationship data directly onto a user's own document, accepting a small amount of data duplication in exchange for avoiding the multiple sequential queries Firestore's model would otherwise require to answer that same question. This kind of tradeoff needs to be made deliberately and early, since retrofitting denormalization onto a data model already in production use is a more disruptive change than making the same decision before any real user data exists.
Where we already know this will not scale forever
It will not scale forever without real backend investment as the product matures — Firestore's query model has real limitations once data relationships get more complex, particularly around querying across collections in ways the document model was not designed for, and Cloud Functions' cold-start latency becomes a more noticeable user-facing problem as usage grows beyond a small early-adopter user base. We were upfront with the client from the start that this architecture is meant to validate the idea fast, not to be the final production architecture at meaningful scale, and we scoped a rough plan for what a migration to a more traditional backend would look like once (and if) the product's growth justifies that investment.
Cost as the product grew past its earliest users
Firebase's usage-based pricing, which felt essentially free during the MVP's first few weeks with a handful of test users, is worth watching closely as real usage grows, since Firestore's per-document-read pricing model can scale in ways that are not always intuitive from a traditional server-cost mental model. We set up billing alerts from day one specifically so a usage spike, whether from real growth or from an inefficient query pattern nobody had noticed yet, would surface as a proactive alert rather than a surprising bill discovered after the fact.
What the client's own team noticed about the tradeoffs
The client's non-technical founders were pleasantly surprised by how quickly bugs got fixed during the pilot phase, since a Firebase-based application has fewer moving infrastructure pieces where a bug can hide compared to a traditional multi-service backend, but their own technical hire, brought on partway through the pilot to start planning the product's next phase, flagged the same Firestore query limitations described above as a real concern for the specific data relationships the product's roadmap called for next. Having that concern surface early, from someone who would actually be living with the architecture's limits going forward, gave the client a clearer, better-informed picture of when a migration to a more traditional backend would actually become necessary rather than treating it as a vague future worry with no concrete trigger attached to it.
A late surprise: Apple's sign-in requirement for App Store submission
Midway through the pilot, the client mentioned a future mobile app submission to Apple's App Store, which as of this year requires apps offering third-party sign-in options to also offer Sign in with Apple. Because Firebase Authentication already supported Apple as a provider alongside email and Google, adding it took an afternoon rather than becoming a blocking dependency discovered later during an actual App Store submission process, which is exactly the kind of small future-proofing benefit that comes from a managed auth provider tracking platform requirements like this on the team's behalf rather than the team needing to track every platform's evolving sign-in requirements itself.
Results
The whole MVP went from kickoff to a usable product in three weeks, giving the client real early user feedback well before a more traditional backend build would have gotten them to the same point, and the security review process we ran before launch is now a standard step on every Firebase project we build, specifically because of how quietly a rules misconfiguration can hide compared to an application-code bug that would typically surface itself through a visible error somewhere.
How we structured Cloud Functions to avoid a common cost trap
A poorly scoped Cloud Function that runs on every single Firestore write, rather than only the specific document changes it actually needs to react to, is a common and easy mistake that can quietly multiply invocation costs as a collection grows. We scoped each of this MVP's functions to trigger only on the specific collection and, where possible, the specific field changes relevant to that function's job — the welcome-email function trigger, for instance, watches only for a new user document's creation rather than any subsequent update to that same document — which kept invocation counts, and therefore cost, proportional to actual meaningful events rather than to total Firestore write volume.
A note on testing security rules directly
Beyond the pre-launch security review described above, we now write automated tests directly against Firestore's security rules using Firebase's local emulator, simulating specific authenticated and unauthenticated requests against the rules themselves rather than relying solely on manual review to catch a permissive rule. This emulator-based testing is what would have caught the profile-document rules mistake automatically had it existed at the time, and it is now a standing part of our Firebase project template going forward.