Why we still pick Flutter + Firebase + AdMob for new mobile apps in 2026

After shipping a pile of apps across iOS and Android, we keep landing on the same boring stack. Here's why Flutter, Firebase and AdMob still win for us in 2026.

Why we still pick Flutter + Firebase + AdMob for new mobile apps in 2026
KEY TAKEAWAYS
  • Flutter still ships one codebase to iOS, Android and web with fewer surprises than React Native in 2026.
  • Firebase Auth, Firestore and Cloud Functions get a solo dev from zero to paying users in a weekend without DevOps.
  • AdMob plus a paywall via RevenueCat is still the fastest way to monetize an app you are not sure people want yet.
  • The stack has real downsides: cold starts on Cloud Functions, Firestore pricing surprises, and AdMob policy strikes that can wipe a weekend.
  • We pick this stack because it is boring and known, not because it is the most exciting thing on Hacker News.

Last month a client asked why we were still pitching Flutter and Firebase for their new app. “Isn’t that kind of 2021?” Fair question. The honest answer is yes, and we don’t care.

We’ve shipped a lot of small mobile apps over the past three years. Photo tools, utility apps, a couple of niche social things that did not make it. Every time we sit down to start a new one, we run through the same internal debate: React Native with Expo, native Swift plus Kotlin, maybe Tauri Mobile if we’re feeling brave. And every time we end up back at Flutter, Firebase, AdMob. Not because it’s exciting. Because we know exactly how long each part takes to build, and we know what breaks.

Here is the actual reasoning, with the warts.

One codebase, two stores, fewer surprises

Flutter renders its own widgets. That used to feel weird (“why isn’t it using native components?”) and now it feels like the whole point. The app looks the same on a Pixel 6 and an iPhone 15 because Flutter is drawing every pixel. No more “it works on iOS but the keyboard pushes the layout up on Samsung devices.”

React Native got better. Expo got a lot better. But we still hit native module version mismatches roughly every other release, and the New Architecture rollout has been a slow grind. Flutter 3.x with Impeller on iOS gives us 60 fps scrolling on a list of 500 items without me having to think about it.

A concrete number: on our last app, a photo gallery that loads thumbnails from Firebase Storage, the entire UI layer including dark mode, settings, paywall and image viewer was about 4,200 lines of Dart. One codebase. Shipped to both stores in the same week.

Firebase is a backend that a solo dev can actually run

I know the arguments against Firebase. Vendor lock-in. Firestore pricing can spike. NoSQL data modeling will eventually bite you. All true.

Now the other side. For a new app where we don’t know if anyone will use it, Firebase gives us:

The alternative is standing up a Postgres on Hetzner, writing auth ourselves or bolting on Supabase, building an admin panel, configuring backups, setting up Sentry. That is maybe two weeks of work before we write a single feature. Firebase is two hours.

When the app finds product-market fit, we can migrate. We have done it. It is not fun, but it is also not the end of the world. And most apps never get that far, which is exactly the point.

A Cloud Function we use on basically every app:

import { onCall, HttpsError } from "firebase-functions/v2/https";
import { defineSecret } from "firebase-functions/params";

const FAL_KEY = defineSecret("FAL_KEY");

export const generateImage = onCall(
  { secrets: [FAL_KEY], timeoutSeconds: 120, memory: "512MiB" },
  async (req) => {
    if (!req.auth) throw new HttpsError("unauthenticated", "Sign in first");

    const { prompt } = req.data as { prompt: string };
    if (!prompt || prompt.length > 500) {
      throw new HttpsError("invalid-argument", "Bad prompt");
    }

    const res = await fetch("https://fal.run/fal-ai/flux/schnell", {
      method: "POST",
      headers: {
        Authorization: `Key ${FAL_KEY.value()}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ prompt, num_images: 1 }),
    });

    if (!res.ok) throw new HttpsError("internal", "FAL failed");
    return await res.json();
  }
);

That is the whole thing. Auth check, input validation, call a model provider, return the result. No Express, no Docker, no nginx config. Deploy with firebase deploy --only functions:generateImage.

Cold starts are real. First call after idle is 1.5 to 3 seconds. We pin minInstances: 1 on user-facing functions once the app is paying for itself. That costs about $6 a month per function.

AdMob plus RevenueCat is still the fastest path to revenue

This is the part where I have mixed feelings. AdMob is not pleasant. The dashboard is from another era, policy strikes can land for reasons that are never fully explained, and ad fill rates in some countries make you want to cry.

But. For a free app where we are testing whether the idea has any pull, banner ads on the home screen and a single interstitial after the user does the main action will tell us within a week if there is enough engagement to be worth a paywall. Last year we ran an app to about 40,000 installs on $0 spend, made roughly $1.10 RPM on AdMob, and used that signal to decide whether to add a subscription. We did. RPU went up 7x.

For the subscription side we use RevenueCat. Apple’s StoreKit 2 is fine now and Google Play Billing 6 is also fine, but RevenueCat gives us a single API across both, plus receipt validation, restore flows, paywalls and analytics. Free up to $2,500 monthly tracked revenue. We have never regretted using it.

The flow we keep landing on: free app, AdMob for the first week, then either add a soft paywall (some features behind subscription) or kill the app. AdMob pays the AI inference bill while we are figuring out if the app deserves to exist.

What this stack is bad at

I want to be clear about where it falls down.

Flutter web is fine for a marketing page or an internal admin, not for a consumer web app. Use Astro or Next for that. We host our marketing sites on Cloudflare Pages and the apps proper stay native.

Firestore costs scale with reads, not data size. If you build a feed app where every user loads 200 documents on open, your bill will surprise you. Cache aggressively or denormalize into a single document.

AdMob will sometimes flag your app for reasons that are not your fault. We had Photo AI Studio’s ads paused for 11 days because of a phantom “navigation issue” the reviewer could not reproduce. We now keep one ad-free build ready to ship the minute that happens.

Flutter hiring is harder than React hiring. If you are building a team, that matters. If you are a solo dev or a two-person studio, it does not.

Why not just use AI to write native Swift and Kotlin?

This is the version of the question I get in 2026. Cursor and Claude Code can write competent Swift now. Why maintain a cross-platform layer at all?

We tried. The output is good. The integration cost is not. Two codebases means two CI pipelines, two crash reporting setups, two analytics implementations, two places where a string typo lives, two App Store review cycles where one platform breaks and the other does not. AI writing the code does not change any of that. The bottleneck is not typing speed. It is the surface area of the system you have to keep in your head.

One Dart file, one Firebase project, one set of secrets. That is what we are buying.

If you want help shipping an app on this stack or arguing us out of it, come talk to us.

FREQUENTLY ASKED

Common questions

Why not React Native with Expo in 2026?

Expo is genuinely great now and we use it for some client work. The reason we default to Flutter is rendering consistency. Flutter draws its own widgets with Impeller, so a complex screen looks identical on iPhone and Android without us writing platform-specific shims. With React Native we still hit native module mismatches and keyboard or safe-area edge cases roughly every release. If you already have a React team, use Expo. If you are starting fresh, Flutter has fewer hidden costs in our experience.

Isn't Firebase vendor lock-in a problem?

Yes, but less than you'd think for early-stage apps. Auth migration is straightforward because Firebase exports password hashes in a compatible format. Firestore data is JSON, exportable any time. Cloud Functions are basically Node, portable to anything. The real lock-in is convenience: once you have Crashlytics, Analytics, Remote Config and Auth working together, you do not want to leave. We have migrated apps off Firebase when economics demanded it. It took about two weeks each time. That is a problem we are happy to have.

How do you handle Firestore cost surprises?

Three rules. One, never read a collection on app open if you can read a single user document instead. Denormalize. Two, cache with the Firestore SDK's offline persistence enabled, which is on by default in Flutter but worth verifying. Three, set up a budget alert in Google Cloud for double your expected monthly cost. We have a $50 alert on most projects and a $500 hard cap. When we hit alerts, it is almost always a missing `.limit()` on a query or a runaway listener.

What about AdMob policy strikes? How do you protect against them?

Keep an ad-free build configuration ready to ship. We use Flutter build flavors and a Remote Config flag so we can disable ads remotely without a new release. Read the AdMob policies properly before you ship, especially the rules around accidental clicks and ad placement near interactive elements. Do not put a banner directly above or below a button users tap often. When a strike does land, respond to the appeal quickly and politely. Most get resolved within a week.

When would you not pick this stack?

Games (use Unity or Godot). Apps that need deep platform integration like custom keyboards, complex widgets, watch apps or CarPlay (go native). Apps with strict data residency requirements where Firebase's region options do not fit. Apps where you already have a strong backend in Postgres or similar and just need a client. And anything where the team is more comfortable in another stack. Boring tech wins, but only if your team finds it boring.

SOURCES
  1. [1]
  2. [2]
  3. [3]
    RevenueCat pricingrevenuecat.com
  4. [4]
    Google AdMob policiessupport.google.com

Related posts