MediumReact Native vs Flutter: What I’ve Learned About Cross-Platform Mobile Development | by Rishav Raj Jaiswal | Sep, 2026 | Medium
Sitemap
Rishav Raj Jaiswal

Rishav Raj Jaiswal

React Native vs Flutter: What I’ve Learned About Cross-Platform Mobile Development

7 min readSep 20, 2026

--

Building a mobile application used to mean making a choice very early in the project:

Android or iOS?

Then came the obvious second question:

Do we really want to build the same application twice?

That’s where cross-platform development became interesting.

Today, frameworks like React Native and Flutter allow developers to build applications for Android and iOS while sharing a significant amount of code.

But after working with mobile development, backend systems, APIs, and native Android, I’ve learned that the interesting part isn’t simply:

“Which framework is better?”

The more useful question is:

Where does cross-platform development work really well, and where do you still need native code?

The promise of cross-platform development

The basic idea is simple.

Instead of:

Android
↓
Kotlin / Java
↓
Android UI
iOS
↓
Swift / Objective-C
↓
iOS UI

we can build:

             Shared Application
|
┌──────────┴──────────┐
↓ ↓
Android iOS
↓ ↓
Native APIs Native APIs

The business logic, networking, state management, validation, and much of the UI can be shared.

That has a huge advantage.

If you have a team building:

  • authentication
  • payments
  • maps
  • booking
  • notifications
  • dashboards
  • search
  • profile management

you don’t necessarily want to implement the same logic twice.

React Native: JavaScript meets mobile

React Native was interesting to me because of its connection to the React ecosystem.

If you’ve worked with React on the web, many concepts feel familiar:

function Profile({ user }) {
return (
<View>
<Text>{user.name}</Text>
</View>
);
}

You get familiar concepts such as:

  • components
  • props
  • state
  • hooks
  • reusable UI
  • declarative rendering

This makes the learning curve much easier for developers who already work with React.

But React Native isn’t simply “React for mobile.”

That’s an important distinction.

Eventually, you will encounter:

JavaScript / TypeScript
↓
React Native
↓
Native Platform
↓
Android / iOS

And when something doesn’t work correctly at the platform level, you may need to understand what’s happening underneath.

That’s where having native development experience becomes extremely useful.

The part people underestimate: native integration

Cross-platform does not mean:

“I never need native code.”

In real applications, you might need:

  • Bluetooth
  • background location
  • camera
  • biometrics
  • push notifications
  • NFC
  • device sensors
  • custom maps
  • native payment SDKs
  • platform-specific authentication
  • background services

Sometimes a library already exists.

Sometimes it doesn’t.

And sometimes the library exists but doesn’t support the exact version of Android or iOS you need.

That’s when you end up writing a native bridge.

For example:

React Native
|
| Bridge / Native Module
|
┌───┴────┐
↓ ↓
Android iOS
Java/Kotlin Swift

This is one reason I think understanding native mobile development remains valuable even when you’re primarily working with React Native.

Flutter took a different approach

Flutter comes from a different philosophy.

Instead of relying heavily on native UI components, Flutter provides its own rendering framework.

The architecture is roughly:

Dart
↓
Flutter Framework
↓
Flutter Engine
↓
Skia / Rendering
↓
Android / iOS

Flutter uses Dart as its programming language.

The widget-based approach is one of the things that makes Flutter interesting.

A screen might look conceptually like:

Scaffold(
appBar: AppBar(
title: const Text('Orders'),
),
body: ListView(
children: [
OrderCard(),
OrderCard(),
OrderCard(),
],
),
);

Everything is essentially composed from widgets.

Once you understand the widget tree, Flutter starts to feel very consistent.

React Native and Flutter solve the same problem differently

This is where the comparison becomes interesting.

AreaReact NativeFlutterLanguageJavaScript / TypeScriptDartUI modelReact componentsWidgetsEcosystemStrong JavaScript/React ecosystemStrong Flutter ecosystemNative integrationNative modules / platform APIsPlatform channels / pluginsWeb developersVery familiarNew language/runtimeUI controlStrongVery strongCode sharingHighHighNative knowledgeStill usefulStill usefulLearning curveEasier for React developersModeratePerformanceGenerally strongGenerally strong

But benchmarks alone don’t tell the whole story.

The real question: what are you building?

Imagine you’re building a food delivery application.

You need:

Login
Home
Search
Restaurant listing
Cart
Payments
Order tracking
Maps
Notifications
Profile

This is an excellent use case for cross-platform development.

Most of the application consists of:

UI
+
API calls
+
State management
+
Business logic
+
Authentication

There is a lot of code that doesn’t need to be written separately for Android and iOS.

Now imagine you’re building an application heavily dependent on:

Bluetooth
Camera
AR
Background processing
Advanced device sensors
Platform-specific hardware

The equation changes.

You might still choose cross-platform development, but the amount of native integration becomes much higher.

Cross-platform doesn’t eliminate architecture

This is another lesson that becomes obvious once an application gets large.

You can have beautiful React Native or Flutter screens and still build a terrible application.

For example:

Screen
↓
API
↓
Everything else

doesn’t scale very well.

A better architecture might separate:

Presentation
↓
State Management
↓
Domain / Business Logic
↓
Repository
↓
API / Local Storage

For example:

                  UI
↓
View Model
↓
Use Cases
↓
Repository
/ \
↓ ↓
REST API Local DB

The exact implementation differs between React Native and Flutter, but the architectural principles remain the same.

React Native architecture can look familiar

A React Native application might be structured around:

components/
screens/
navigation/
hooks/
services/
store/
api/
utils/
native/

For example:

OrderScreen
↓
useOrder()
↓
OrderService
↓
API Client
↓
Spring Boot Backend

This becomes particularly useful when your backend is built using something like:

React Native
↓
REST API
↓
Spring Boot
↓
Kafka
↓
Microservices
↓
Database

Now mobile development isn’t an isolated frontend problem.

It’s part of a larger distributed system.

Don’t forget offline-first applications

One area that deserves much more attention is offline support.

Mobile networks aren’t reliable.

Get Rishav Raj Jaiswal’s stories in your inbox

Join Medium for free to get updates from this writer.

Your application needs to work when:

  • the user enters an elevator
  • network switches from Wi-Fi to cellular
  • connectivity disappears
  • API calls timeout
  • the backend is temporarily unavailable

Instead of:

Button
↓
API
↓
Success

you may need:

User Action
↓
Local State
↓
Local Database
↓
Sync Queue
↓
Network Available?
↓
API
↓
Server

This architecture becomes particularly important for applications involving:

  • field workers
  • delivery
  • transportation
  • inventory
  • payments
  • tracking
  • offline forms

Cross-platform frameworks can help build the UI, but they don’t solve the distributed-systems problem for you.

State management becomes important as applications grow

A small application can survive with local component state.

A large application usually cannot.

Imagine:

User
├── Authentication
├── Cart
├── Orders
├── Notifications
├── Location
└── Preferences

Multiple screens may depend on the same state.

In React Native, you might use approaches involving:

Context
Redux
Zustand
React Query
Custom Hooks

In Flutter, you might see:

Provider
Riverpod
Bloc
Cubit

The specific library matters less than understanding the problem you’re solving.

Don’t introduce a global state-management solution just because every tutorial uses one.

Use it when state actually needs to be shared, persisted, synchronized, or observed across parts of the application.

Performance: don’t blame the framework too quickly

One of the most common conversations around cross-platform development is:

“Is Flutter faster than React Native?”

or:

“Is native always faster?”

The answer is more complicated.

Performance problems can come from your application architecture.

For example:

Large list
↓
Too many renders
↓
Expensive calculations
↓
Unnecessary network calls
↓
Poor image handling
↓
Slow UI

The solution isn’t automatically changing frameworks.

In React Native, understanding things like:

memo
useMemo
useCallback
FlatList
virtualization

can make a significant difference.

In Flutter, understanding:

widget rebuilds
const widgets
ListView.builder
rendering
state boundaries

is similarly important.

The framework gives you the tools.

You still have to use them correctly.

Maps are a perfect example

Maps look simple until you actually build a production application around them.

You might need:

Current location
Markers
Routes
Geofencing
Tracking
Background location
Map gestures
Location permissions

And suddenly your “cross-platform” application is talking directly to:

Android Location APIs
+
iOS Location APIs
+
Map SDK
+
Background services

This is where platform knowledge becomes extremely valuable.

I’ve found that cross-platform development works best when you think of it as:

shared application development + native platform integration

rather than:

write once and forget the platforms exist.

React Native isn’t replacing native development

And Flutter isn’t either.

Native development is still important.

The relationship is closer to:

                  Mobile Application
|
┌──────────┴──────────┐
↓ ↓
Cross-platform layer Native layer
↓ ↓
Shared application Platform APIs

The cross-platform layer handles the majority of the product.

The native layer handles the places where the platform matters.

That’s a much more realistic mental model.

What about React Native + React Native Web?

This is another interesting direction.

If your organization already has a React ecosystem, you can potentially share concepts across:

Web
↓
React
Mobile
↓
React Native

And with appropriate architecture, some business logic can be shared:

            Shared
Business Logic
|
┌──────┴──────┐
↓ ↓
Web Mobile
React React Native

That can be extremely valuable for teams already invested heavily in TypeScript and React.

But again, don’t force 100% code sharing.

Sometimes platform-specific code is cleaner.

Trying to make Android, iOS and Web behave identically can actually make the codebase harder to maintain.

The architecture I prefer

For a typical enterprise mobile application, I’d think about the system in layers:

┌──────────────────────────────┐
│ Mobile UI │
│ React Native / Flutter │
├──────────────────────────────┤
│ State / Presentation │
├──────────────────────────────┤
│ Business Logic │
├──────────────────────────────┤
│ Repository / API │
├──────────────────────────────┤
│ Local Storage │
├──────────────────────────────┤
│ Native Platform │
├──────────────────────────────┤
│ Android / iOS │
└──────────────────────────────┘
|
↓
Backend Services
|
┌────────┼─────────┐
↓ ↓ ↓
REST API Kafka Database

This gives you flexibility.

The UI framework can change.

The backend can evolve.

Native functionality can be isolated.

Business logic doesn’t have to be tightly coupled to the UI.

So, Flutter or React Native?

I don’t think there is a universal answer.

If your team already has strong React and TypeScript experience, React Native can fit naturally into the existing engineering ecosystem.

If you want a highly controlled UI framework with a unified widget system and are comfortable adopting Dart, Flutter is a strong option.

But I would make the decision based on more than framework benchmarks.

Look at:

Team expertise

Existing codebase

Native SDK requirements

Backend architecture

Offline requirements

Performance requirements

Development velocity

Hiring

Long-term maintenance

Third-party library maturity

These factors usually matter more than whether one framework wins a benchmark.

The bigger lesson

Cross-platform development isn’t really about writing code once.

It’s about reducing duplication without hiding the platform.

That’s an important distinction.

The best cross-platform applications don’t pretend Android and iOS are the same.

They share what should be shared:

Business Logic
API Layer
State
Models
Most UI
Validation
Networking

And isolate what should remain platform-specific:

Permissions
Background Services
Hardware
Native SDKs
Platform UX
OS-specific behavior

That’s where I think cross-platform mobile development is heading.

Not:

Write once, run everywhere.

But:

Share what makes sense, specialize where the platform matters.

And for developers coming from web or backend engineering, that’s probably the most important mindset shift.

You don’t have to choose between being a “React developer,” “Flutter developer,” or “native developer.”

The stronger mobile engineer understands the layers underneath all three.

Because frameworks change.

The architecture doesn’t.

--

--