Flutter vs React Native
Cross-platform mobile titans compared: Flutter's Skia rendering vs React Native's native bridges, performance benchmarks, ecosystem, and 2026 enterprise adoption.
A managed React Native framework set up with Node.js LTS, reversible thanks to CNG
The core React Native setup, giving full control over the native toolchain
In 2026 the default answer is Expo + CNG: since `expo prebuild` regenerates the native folders, "eject" is no longer a one-way door, the config plugin system covers most native configuration, and EAS Build's free tier is enough for a small-to-mid-sized project. The reasons that justify Bare React Native are narrow but real: a custom toolchain EAS doesn't support, a mandatory on-prem CI requirement, or a very rare native SDK. If none of those apply, start with Expo.
| Category | Expo | Bare React Native |
|---|---|---|
| Performance | 8/10 | 8/10 |
| Ease of Learning | 9/10 | 6/10 |
| Ecosystem | 8/10 | 8/10 |
| Community | 8/10 | 8/10 |
| Job Market | 7/10 | 8/10 |
| Future-Proof | 8/10 | 7/10 |
// Expo — adding a native permission via app.config.ts + a local config plugin (TypeScript)
// plugins/withCameraUsage.ts — config plugin that adds camera permission to Info.plist
import { ConfigPlugin, withInfoPlist } from "expo/config-plugins";
const withCameraUsage: ConfigPlugin = (config) =>
withInfoPlist(config, (config) => {
config.modResults.NSCameraUsageDescription =
"Profil fotoğrafı çekmek için kameraya erişim gerekiyor";
return config;
});
export default withCameraUsage;
// app.config.ts — the plugin is referenced by file PATH (requires npm i -D tsx)
import "tsx/cjs";
import { ExpoConfig, ConfigContext } from "expo/config";
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: "MyApp",
slug: "my-app",
version: "1.0.0",
plugins: [["./plugins/withCameraUsage.ts"], "expo-router", "expo-updates"],
updates: { url: "https://u.expo.dev/your-project-id" },
runtimeVersion: { policy: "appVersion" },
});
// Terminal: generate the native folders (CNG) and apply them
// npx expo prebuild --clean
// Run EAS Build and publish an OTA update
// eas build --platform all --profile production
// eas update --branch production --message "Bug fix: login crash"// Bare React Native — package installation + manual native configuration (TypeScript)
// 1) Install the package: autolinking links it, fetch pods, rebuild
// $ npm install react-native-vision-camera react-native-nitro-modules react-native-nitro-image
// $ npx pod-install
// $ npm run ios # Android: npm run android
// 2) Add permissions MANUALLY — this step is not part of autolinking
// ios/MyApp/Info.plist:
// <key>NSCameraUsageDescription</key>
// <string>We need camera access to take a profile photo</string>
// android/app/src/main/AndroidManifest.xml:
// <uses-permission android:name="android.permission.CAMERA" />
// 3) Usage on the JS side (shared code)
import React, { useEffect } from "react";
import { Camera, useCameraPermission } from "react-native-vision-camera";
function ProfileCamera() {
const { hasPermission, requestPermission } = useCameraPermission();
useEffect(() => {
if (!hasPermission) requestPermission();
}, [hasPermission, requestPermission]);
return <Camera style={{ flex: 1 }} isActive={true} device="back" />;
}
export default ProfileCamera;
// 4) Upgrading (0.86 -> 0.87): there is NO CLI command for this
// Upgrade Helper (web): https://react-native-community.github.io/upgrade-helper/
// -> apply the diff manually to Podfile.lock, build.gradle, AppDelegate.swift
// 5) Your own CI pipeline (GitHub Actions, summary)
// - run: npx pod-install
// - run: xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration ReleaseIn 2026 the default answer is Expo + CNG: since `expo prebuild` regenerates the native folders, "eject" is no longer a one-way door, the config plugin system covers most native configuration, and EAS Build's free tier is enough for a small-to-mid-sized project. The reasons that justify Bare React Native are narrow but real: a custom toolchain EAS doesn't support, a mandatory on-prem CI requirement, or a very rare native SDK. If none of those apply, start with Expo.
Get Free ConsultationIn 2026 the default answer is Expo + CNG: the config plugin system covers most native modules, EAS Build's free tier (15+15 builds/month) is enough for a small-to-mid-sized project, and thanks to `expo prebuild`, dropping down to native code is no longer an irreversible decision. The real reasons that justify bare RN: a custom toolchain EAS doesn't support, a mandatory enterprise on-prem CI requirement, or a very rare native SDK that a config plugin can't cover.