Quick answer
An enterprise mobile stack is the framework, build service and release process your company runs its apps on for years. Choose one by writing your security, identity and device requirements as testable statements, shipping one real feature through your release process with each finalist, and comparing the upkeep each option leaves your teams. If you already ship native apps, you can adopt a new framework one screen at a time.
Which requirements should rule a stack out?
The pilot demo went well. Then a Slack message lands from the identity team: "Does this support our device-bound credentials, and who can see the signing keys?" Ten minutes later, field operations asks what the app does after a scanner has been offline for a whole shift. Either question can decide the stack, so get both answered before anyone presents an architecture diagram.
Start by naming the app and where it runs. A retail app installed from the App Store has different distribution and device assumptions from an internal app on managed warehouse scanners, and the word "enterprise" tells you very little about either.
Write each must-have as a statement someone can test. "Enterprise security" is too broad to check. "A signed-out user cannot recover the previous user's cached customer records" is testable. "Works offline" needs a duration and a list of the actions that keep working without a connection.
Keep hard requirements apart from preferences. A vendor SDK your app cannot ship without can remove an option on day one. Familiar syntax can break a tie between the finalists, but don't let it quietly become a gate.
Give every requirement two owners. Product owns the user outcome, and an engineering or security specialist owns how it gets checked. Procurement can review a service agreement; no service agreement shows that your app survives a failed data migration.
For the security list, start from OWASP MASVS, which groups mobile security requirements into areas such as storage and authentication. Pick the controls that apply to your app and turn them into tests. Choosing a framework does not prove those controls exist. A managed build service can lock down its own machines while your app still writes a session token to its logs, so the build vendor's security and your app's security need separate owners.
How much code should your iOS and Android apps share?
Shared code cuts duplicate work in the app layer, and you still own platform-specific behavior on each platform. The frameworks differ in what they share. Capacitor runs a web app inside a native runtime on iOS and Android. Flutter draws its UI with its own rendering system and supports native interop. Kotlin Multiplatform shares business logic written in Kotlin and can leave the UI fully native, with Compose Multiplatform as an optional shared UI layer. .NET MAUI builds native mobile and desktop apps with C# and XAML. React Native combines React and TypeScript application code with native platform integration.
| Stack | Best for | Question your proof of concept must answer |
|---|---|---|
| Capacitor | A web app whose interaction patterns already suit a phone | Does the installed app meet your hardware and usability requirements? |
| Flutter | Teams with Dart skills that want one shared UI | Can you keep the plugins and platform-specific code you need maintained? |
| .NET MAUI | An existing C# and .NET team | Do the SDKs and device features you need work, and will they stay maintained? |
| Kotlin Multiplatform | Separate native teams with mature UIs that duplicate business logic | Does the shared module cut duplicate change work? |
| Native Swift and Kotlin | A product defined by one platform or by platform-specific UI | Is a shared layer solving a real problem? |
| React Native | React and TypeScript teams shipping the same product on both platforms, including inside an existing native app | Do your required native integrations and accessibility behavior meet your bar? |
Don't make shared-code percentage the goal. For a company with two mature native teams, a shared validation engine can pay for itself while the screens stay separate, and a complicated shared abstraction can cost more than two small platform-specific implementations.
Can you adopt a new framework inside the app you already ship?
Yes. React Native's guide for existing apps covers adding a single view or user flow to a native Android or iOS app. Flutter calls the same idea add-to-app: a Flutter module renders part of the app while the rest stays on your existing code. Kotlin Multiplatform can start smaller still, with one shared Kotlin module that both native apps call.
Brownfield adoption, as adding a framework to an existing native app is called, changes the question. You stop asking which framework to rebuild in and start asking which screen goes first and how the new code reaches the native build. A separate React Native or Flutter team can ship its screens as prebuilt native libraries that your iOS and Android engineers consume like any other dependency. One team that edits both sides every week may prefer to keep everything in one repository and build it together.
A greenfield demo hides brownfield costs. The new runtime uses memory and startup time inside your app. The host and the new code can bring clashing versions of the same native dependency, and somebody has to own the contract between them: what data crosses, who owns the session. Run the proof of concept inside your real host app.
Who controls builds, signing and releases?
Your framework and your build service are linked decisions that you can make separately. Draw the path a change takes from a pull request to a user's phone. Mark where signing credentials are used and who can approve a release. Then check how the engineer on call finds the exact build behind a production crash report.
Ask each vendor to show you the controls live, using your own roles. Single sign-on on a web dashboard says nothing about what a command-line token can do. A protected release job does not protect a second route that can publish directly.
| Area | What to ask the vendor to show you |
|---|---|
| Access | The real roles and token permissions your developers and CI jobs use |
| Release control | An approval step tied to one specific build |
| Traceability | Source commit, build record and release history for the same change |
| Recovery | A tested way to restore service or ship a replacement release |
| Vendor dependence | A documented fallback and the data you would need to use it |
| Support | A contract commitment that matches the support path you need |
How does the stack change hiring and team structure?
Start with the engineers you already employ. A company with a large React web team can move some of those engineers onto React Native screens without learning a new language. A .NET shop can make the same argument for .NET MAUI, and two strong native teams can make it for Kotlin Multiplatform.
Whatever you pick, keep people who own iOS and Android behavior. Someone still has to read a native crash, update a native SDK, keep code signing working and answer store review questions on each platform. Those jobs can live inside one mobile team instead of two platform teams, but they do not go away.
Name owners for the work nobody demos: framework upgrades, third-party SDK updates and the release pipeline. A project parked on an unsupported dependency has deferred work, even if it looks like stability for a year.
Run a handover test before you sign anything. Have a second engineer build the proof of concept from its written instructions alone, update one dependency or change one native setting, then produce another build. Anything that only worked because of the author's laptop shows up here, and you get a preview of your next hire's first week.
How do you run a proof of concept that answers the hard questions?
Pick a feature that pulls in the teams most likely to block a real release. Sign-in plus an offline record update teaches you more than a static dashboard ever will.
Use representative devices and the identity environment your security team approves for testing. Include one failure that matters to the business, such as losing the connection before the server confirms a save.
Ship the prototype through your intended release process. A build compiled on one engineer's laptop tells you nothing about whether the organization can keep signing working or reproduce the same build next month.
If you are extending or replacing an existing app, install the new build over the current production version. Data and sessions already on users' phones are part of the product, and the new code has to read them or migrate them in a tested way.
Then ask the engineers who will own the code to make a follow-up change. A second change shows whether the code makes sense to someone other than its author.
Keep the exercise small, and write down the questions it did not answer. A short acceptance record keeps everyone on the same definition of done:
What will the stack cost to run over the app's life?
A subscription price is easy to see. The engineer who quietly keeps an undocumented release script alive is much easier to miss.
Build the cost model from your own work: implementation, upkeep of platform-specific integrations, build infrastructure, test devices and the hours spent keeping the release path working. Split one-time migration cost from recurring cost, and write your assumptions next to the numbers.
For a shared-code proposal, estimate the duplicate changes it would remove, then subtract the work of maintaining the line between shared and native code. Skip generic claims that cross-platform saves some fixed percentage; your app's native requirements and existing code decide the real number.
Plan the exit too. For each external service, write down which configuration and builds you control and roughly what moving the job elsewhere would take. An exit plan nobody can follow is no plan at all.
Finish with a written decision: which option meets the must-haves, why it fits your teams, and what would make you revisit it.
Where Expo fits
Expo is a framework and set of cloud services for React Native apps, so it belongs in your evaluation when React Native is on the shortlist, for a new app or for screens added to an existing native one. EAS Build builds iOS and Android apps on hosted machines and can manage signing credentials. EAS Workflows chains build, submit and update jobs, and both can run next to the CI system you already have.
For an existing native app, Expo's brownfield overview describes two ways in. The isolated approach packages your React Native screens as an Android AAR and an iOS XCFramework, so native engineers consume them without installing Node.js or React Native tooling. The integrated approach keeps the React Native code inside the native project, for a team that changes both sides together. The overview lists the Expo SDK, Expo Router, EAS Build, EAS Submit and EAS Update as working in brownfield apps, and the Expo development client as not supported there.
Expo's governance controls map to specific lines in a requirements matrix. Organization accounts have owner, admin, release manager, developer and viewer roles, and a protected update channel limits who can publish to it. Single sign-on uses OpenID Connect with identity providers including Okta, OneLogin, Microsoft Entra ID and Google Workspace. The pricing page lists SSO and an EAS SOC 2 Type 2 report on the Production and Enterprise plans, and a 99.9% uptime SLA on Enterprise. Audit logs are an Enterprise plan feature and keep a record of EAS actions for a year and a half.
Continuous Native Generation (CNG) generates the iOS and Android projects from your app config. Decide up front whether you will use CNG or maintain the native projects by hand, because unrecorded manual edits mixed into generated projects make later upgrades hard to reason about.
Limitations
Support for integrating Expo modules into existing native projects is in alpha, and not every Expo tool works in a brownfield app yet, so give that path its own proof of concept inside your host app. No framework makes an app compliant on its own; procurement and app-level security tests stay separate work. Vendor features, plans and contracts change, so record the date and source of every vendor fact in your evaluation.
Next step
Pick the relevant controls from OWASP MASVS and add them to a requirements matrix owned by the teams that will approve and operate the app. Then choose the one feature your proof of concept will ship.
Verified on 12 September 2026.
