Choose a PWA when your product is content or a straightforward tool and you want one codebase and no store review. Choose cross-platform (React Native with Expo, or Flutter) when you need store presence, solid push, and device features without maintaining two apps. Choose fully native when the product depends on deep platform features or top graphics performance.
Start with the hardest required device or offline workflow and prototype it on the actual platforms you must support.
The three options
PWA. A website with a web app manifest and a service worker, which can be installed to the home screen. You ship with the web stack and deploy like a website. See MDN's PWA guide.
Native. Platform-specific applications, commonly Swift for iOS and Kotlin for Android, with access to the APIs the operating system exposes and permits.
Cross-platform. A shared application codebase with platform-specific build targets and different rendering architectures. React Native uses JavaScript/TypeScript and real native views, and Expo provides tooling on top. Flutter uses Dart and draws its own UI.
Comparison
| PWA | Cross-platform (RN/Expo, Flutter) | Native | |
|---|---|---|---|
| Codebases | One (the website) | One for both mobile platforms | Two |
| Store distribution | Optional; mainly via the web | Yes | Yes |
| Performance | Browser runtime and application design determine limits | Profile the actual rendering and native-module workload | Direct platform control; still requires profiling |
| Offline | Browser storage, caching and a designed sync strategy | Local storage and a designed sync strategy | Local storage and a designed sync strategy |
| Device APIs | Verify support in each target browser | Verify modules, permissions and native extension needs | OS APIs remain subject to permissions and restrictions |
| Push notifications | Android: yes. iOS: installed Home Screen apps only | Yes, both platforms | Yes |
| Updates | Instant, on deploy | Store release; compatible runtime updates only where store policies permit | Store release |
| Typical team | Web developers | Web/JS or Dart developers | Platform specialists |
Performance
For forms, lists, dashboards, and content, a well-built PWA feels fine. React Native uses native platform views, while Flutter has its own rendering architecture. Test animation, camera and graphics workloads on representative devices; architecture alone does not establish which implementation will be faster. For a typical business app, the bigger performance risk is network design and bundle size, not the framework.
Offline
A PWA can cache the app shell and data using service workers and browser storage, but storage quotas and eviction rules vary by browser, and you manage sync yourself. See web.dev on storage. A mobile application can use a local database, but conflict handling, retries and background execution still need explicit design and device testing. If offline is a core feature (field work, patchy connectivity), lean toward cross-platform or native.
Device APIs
Camera, geolocation, and basic sensors work on the web. Bluetooth, NFC, background location, contacts, and many hardware features are inconsistent or unavailable, especially on iOS Safari. Check each API you need against the current browser support tables before committing. React Native and Flutter reach most native features through modules, and you can write native code for the rest.
Push notifications on iOS web apps
Web Push on iPhone and iPad has worked since iOS and iPadOS 16.4, with conditions. According to WebKit's announcement:
- The web app must be added to the Home Screen, and its manifest must set
displaytostandaloneorfullscreen. - Permission must be requested in response to a direct user action, such as tapping a subscribe button.
- It uses the Push API, Notifications API, and service workers. Notifications go through Apple's push service, and no Apple Developer Program membership is needed.
- Badging is supported for the icon.
The practical problem is the install step. iOS does not show an automatic install prompt, so users must add the app to the Home Screen from the share menu (web.dev on installation). If push is central to engagement, the installation step creates a conversion requirement to test. Design an in-app explanation, and measure how many people actually install.
Store distribution
Stores give discovery, trust, and a payments and update channel, at the cost of review cycles and platform rules. Direct web distribution avoids a store review for web releases. Cached clients may still run older code, so test service-worker update and compatibility behaviour. If your customers expect to find you in the App Store or Play Store, or if your enterprise clients use managed deployment, confirm the required public or private distribution route. Expo's submission tooling helps automate store release for React Native builds.
Cost
The main driver is codebase count. A PWA adds incremental work to a web project you probably need anyway. Cross-platform covers iOS and Android with one team and mostly one codebase. Separate native clients add platform-specific implementation and testing, though the backend and parts of the design work can be shared. Cross-platform is not free of platform work: you still handle store accounts, signing, permissions, and platform-specific bugs. Treat any saving as indicative, and get estimates for your specific scope.
When each is right
Pick a PWA when
- The product is already a web app or content site.
- You want quick iteration and no store dependency.
- Push is a nice-to-have, or your users are mostly on Android.
Pick cross-platform when
- You need App Store and Play Store presence.
- You need reliable push on both platforms, offline sync, or camera and location in the background.
- You have a small team and want one codebase.
Pick native when
- The product depends on advanced graphics, AR, or the newest platform features.
- You have the budget and team for two apps.
A sensible path for many startups: ship the web product first, add PWA basics, and move to cross-platform when store presence or push demands it. Apex builds React Native apps with offline and sync support, and you can read about that in app design and development. For stack choices around it, see choosing a startup tech stack.