One Codebase, Both Stores

Cross-Platform App Development, With the Trade-Offs Said Out Loud

React Native and Flutter are genuinely good answers for a lot of apps and genuinely wrong for some. Most agencies only tell you the first half. Here is the whole thing, including where we would talk you out of it.

  • We build native too
  • Framework chosen per project
  • Recommendation on the first call
The same app running side by side on an iPhone and an Android handset from one shared codebase
The Decision

It Is Not a Discount. It Is a Different Set of Compromises.

The pitch for cross-platform is usually money: one team, one codebase, half the cost. That pitch is half true and it hides the part that actually matters, which is that you are choosing a different shape of risk rather than a cheaper version of the same thing.

What you are really buying is a single place to fix a bug and a single place to add a feature, for the entire life of the product. What you are really paying is a dependency on a framework you do not control, sitting between your code and two platforms that change every year.

For a large majority of apps — the ones made of screens, lists, forms, accounts and API calls — that is a good trade and we will say so. For the rest it is not, and we will say that too, even though it is the more expensive advice for you and the less profitable advice for us.

Straight Answer

What You Genuinely Gain, and What You Genuinely Give Up

Not the marketing version of either column.

What you gain

Mostly After Launch, Not Before It

  • A bug is diagnosed once and fixed once, instead of twice by two people who write it up differently
  • Both platforms stay genuinely at feature parity, rather than Android quietly running three releases behind
  • One team to hire, brief, onboard and keep, which matters more at four people than at forty
  • One set of business logic, so the two apps cannot disagree about what a rule means
  • Faster iteration once live, because shipping to both stores is one piece of work

What you give up

Small Things That Add Up

  • Same-week access to new OS features. You wait for the framework, or you write the bridge.
  • A layer between you and the bug. Some problems are in the framework, and then you are waiting on someone else.
  • A few megabytes of app size you did not choose, which matters on a cheap phone with a full disk
  • The last few percent of feel: scroll physics, keyboard behaviour, selection menus, transition timing
  • A periodic upgrade tax. Nobody sits on a three-year-old framework version and stays shippable.

Notice that nothing in the right-hand column is about whether it works. It works. The column is about where the friction moves to.

Economics

The Saving Is Not in the Build. It Is in Year Two and Year Three.

People compare the two quotes and are disappointed that one codebase does not cost half. That is because the first invoice is the wrong place to look.

Where the money goesTwo native codebasesOne shared codebase
DesignTwo platform treatments of the same flowsStill two treatments. No saving here at all.
Application codeWritten twice, in two languages, by two peopleWritten once. This is the real reduction.
Platform-specific workIncluded by definitionStill needed at the edges, and it is native code either way
Device testingBoth platforms, full matrixBoth platforms, full matrix. No saving.
Store submission and listingsTwo of everythingTwo of everything. No saving.
Fixing a bug after launchDiagnosed and fixed twiceOnce, and it ships to both stores together
Adding a feature after launchBuilt twice, and the two drift apartOnce, and parity is automatic
Annual OS releasesTwo sets of breaking changes to absorbFramework upgrade, plus whatever it did not cover
Team you need in year threeiOS and Android capability, both kept warmOne capability, plus occasional native help

An illustrative breakdown of where effort sits, not a quotation. The shape is consistent across projects; the amounts depend entirely on your app. Run your own figures through the app cost estimator or see pricing.

Year one looks close

Design, testing and store work are duplicated regardless, so the shared codebase saves on one line out of five. Expect a meaningful difference, not a halving, and be suspicious of anyone quoting a halving.

Years two and three decide it

By then you have shipped more code after launch than before it. Every fix and every feature happens once instead of twice, and that compounds quietly until it dwarfs the original difference.

Where the maths breaks

If the app accumulates a lot of platform-specific code, you are maintaining two codebases plus a framework. That is the worst of both, and it is why the limits below are worth reading before you commit.

The Limits

Where Cross-Platform Actually Runs Out

Three places, consistently. If your app lives in one of them, the shared codebase stops paying for itself and starts costing you.

Heavy or gesture-driven animation

  • Anything that has to track a finger at full frame rate on a cheap phone, not just on a flagship
  • Complex shared-element transitions between screens, where a frame or two of lag is the whole effect
  • Custom drawing that updates continuously: charts that follow a drag, canvases, games
  • It can be done. It takes specialists, it takes longer than the native equivalent, and it is the first place a demo falls apart on real hardware.

Deep hardware access

  • Custom camera capture with manual control, or processing frames as they arrive
  • Bluetooth peripherals, especially pairing and reconnection behaviour that differs per platform
  • Sustained background location, step counting, health and sensor streams
  • On-device machine learning, audio processing, offline maps and anything else that is really native work wearing a wrapper
  • Every one of these ends up as a native module, and enough of them means you have written two native apps with an extra layer on top

Platform-specific expectations

  • Apps where iOS users expect an iOS app and Android users expect an Android one, not a compromise between them
  • Deep system integration: widgets, Live Activities, quick settings tiles, share extensions, watch apps
  • Products where a designer has opinions about scroll physics and keyboard behaviour, and is right to
  • Anything sold on craft, where the last few percent of feel is the reason people pay

One useful test: write down the five hardest things the app has to do. If two or more of them are on this page, native is probably the honest recommendation, and we will give it.

Native Modules

The Escape Hatch, and the Point Where It Stops Being One

Neither framework traps you. Both let you drop into Swift or Kotlin and expose it to the shared code. Understanding what that costs is the difference between a sensible plan and a slow-motion mistake.

How it actually works

You write the platform code twice, once in Swift and once in Kotlin, and define a small interface that the shared codebase calls. The shared side sees one function; underneath, two implementations do the platform-specific work. For most needs somebody has already published a package that does exactly this, which is why the ecosystem matters as much as the framework.

Where it gets expensive is the boundary. Anything crossing it has to be serialised, so passing a lot of data frequently — camera frames, sensor streams, large lists updating continuously — is precisely the case the boundary is worst at. That is not a bug; it is the shape of the architecture, and designing around it is most of the skill.

What it costs you, honestly

  • Two implementations to write, test and keep in step, plus the interface between them
  • People on the team who can actually write Swift and Kotlin, which is the part that quietly disappears from other agencies
  • A third-party package that is unmaintained becomes your code the day it breaks
  • Debugging spans two worlds, so a crash can start in shared code and end in a native stack trace
  • Past roughly a fifth of the app, the shared codebase is no longer the thing you are maintaining

We audit dependencies before committing to a stack, because the honest version of a cross-platform estimate depends on which packages you are trusting and how alive they are.

Choosing One

React Native or Flutter

Both are mature, both are backed by very large companies, and both are running apps on your phone right now. The choice is usually settled by hiring and by what you already have, not by a benchmark.

Question you should actually askPoints to React NativePoints to Flutter
Who maintains this in three years?Any competent JavaScript or TypeScript developer can get productiveA smaller pool, but one that is usually mobile-native in mindset
Do you already have a web product?Types, validation and business logic can genuinely be sharedNo overlap. Dart is its own world.
How custom is the design?Fine, with more effort once you leave platform components behindIts natural home. Custom UI costs the same as standard UI.
Should it feel like each platform?Closer by default, because it uses the real componentsAchievable, but you are recreating the behaviour rather than inheriting it
Is app size tight?Generally the lighter of the twoA larger floor, because it ships its own rendering engine
How much animation is there?Good, with care around lists and gesturesConsistently strong, and the reason a lot of teams pick it

A deliberately even summary. We do not have a house framework, and on some projects the correct recommendation is neither of them.

Who This Is Not For

The Projects We Turn Away From Cross-Platform

These come up often enough to be worth stating plainly, before anyone has spent money.

Only one platform is needed, now or ever. Then there is nothing to share and only overhead to carry.
The app is a wrapper around hardware: a camera product, a Bluetooth device companion, a fitness tracker.
The roadmap is built on adopting new OS features in the weeks after they are announced.
Someone wants a desktop and a web version out of the same codebase too. That ambition usually costs more than it saves.
You have an in-house iOS or Android team already. Adding a framework they do not use is an organisational problem, not a technical one.
The only reason for choosing it is that it sounded cheaper. That reason does not survive contact with year two.
FAQ

Cross-Platform Questions We Get Asked

Will users be able to tell the app is cross-platform?

Not from a screenshot, and usually not from a minute of use. They notice it in the seams: a scroll that decelerates slightly differently from every other app on the phone, a keyboard that pushes the layout around in an unfamiliar way, a text selection menu that is not the one the system usually shows, a transition that is a frame or two late. Individually none of that is fatal. Together it produces the vague sense that an app is not quite from here, which people express as the app feeling cheap rather than as a specific complaint. The gap is much smaller than it was, and careful work closes most of it, but anyone who tells you it is zero has not looked hard enough.

How much does one codebase actually save over three years?

Less than half on the build and more than half on everything after it, which is the opposite of what most people assume. The initial build does not halve, because design still has to cover two platforms, testing still has to cover both sets of devices, and the store work is duplicated no matter what the code looks like. Where the saving compounds is maintenance: one bug fixed once, one feature built once, one library upgrade instead of two, one release process. Over three years, maintenance and iteration usually outweigh the original build, so the shared codebase wins on total cost even when the first invoice looks closer than expected. It stops being true if the app ends up with large amounts of platform-specific code, because then you are maintaining two codebases with extra steps.

Can we start cross-platform and move to native later?

Yes, and it is a legitimate plan, but be clear that it is a rebuild rather than a migration. Screens do not convert. What does carry over is everything that turned out to be the expensive part: the backend and its API, the data model, the design system, the analytics you have already defined, the store listings and the accounts. In practice a rewrite of a proven app is far cheaper and far faster than the original build was, because the arguments are settled and somebody can simply follow the app that already exists. The version of this that goes wrong is drifting into it: adding native code piece by piece until you are paying for both approaches and getting the benefits of neither.

What happens when Apple or Google ships a new platform feature?

You wait, or you write the bridge yourself. When a new capability arrives in an OS release, native apps can use it as soon as the tooling supports it. A cross-platform app can use it once either the framework exposes it or somebody writes a native module that reaches it. For a mainstream feature that is often weeks to months, and for something niche it may be never, in which case you are writing the native code on both sides yourself. This matters more than people expect for anything tied to the annual OS release cycle, and hardly at all for an app made of screens and API calls. It is one of the questions we ask at scoping, because the answer changes the recommendation.

Is a cross-platform app slower than a native one?

For what most apps do, no, and users cannot tell. Loading a screen, fetching data, rendering a list of a reasonable length and handling a form are all fast enough that the framework is not the bottleneck; the network usually is. The differences appear at the edges. Long lists with complex cells need more care than they would natively. Animation that has to track a finger at sixty frames a second on a cheap phone is harder. Startup time is generally a little longer because a runtime has to come up. Heavy on-device work, such as image or video processing, belongs in native code regardless of which framework wraps it. We set performance targets, including cold start and scrolling, as acceptance criteria rather than treating them as something to look at if anyone complains.

Which is the safer long-term bet, React Native or Flutter?

Both are backed by very large companies, both run apps you already use, and neither is going away on the timescale of your project. The honest risk is not abandonment, it is staffing and drift. React Native is JavaScript and TypeScript, so the hiring pool overlaps with every web team on earth and a web developer can be useful on it quickly. Flutter is Dart, which is a smaller pool but a more consistent one, and Flutter developers tend to be mobile people rather than web people who moved sideways. The second risk applies to both: upgrades. Neither framework lets you sit on an old version for three years, because the platforms move and the ecosystem follows. Budget for periodic upgrade work either way, and pick the one your future team can actually staff.

Get a Straight Recommendation, Not a Pitch

Describe the app and we will tell you whether cross-platform is right for it, which framework we would use, and when we would advise going native instead.