React Native Architecture Decisions That Become Expensive Later

The React Native choices that quietly determine how your team builds, releases, and recovers for years — and where EAS actually helps.

31 min read
Share:
React Native Architecture Decisions That Become Expensive Later

The Bug That Took Five Days to Fix (illustrative scenario)

In this illustrative scenario, a production bug is found on Friday at 9:00 AM.

The fix is a one-line JavaScript change. It's reviewed, merged, and ready by 9:20.

Users may not get it until Wednesday, depending on store review and rollout timing.

We've been in that meeting.

We've also been in the other one: a production issue is identified at 9:00, fixed and verified before 9:30, and made available to a rollout cohort. Delivery still depends on connectivity and the app's update-check or relaunch behaviour.

Same kind of bug. Same kind of team.

The difference wasn't the code. It was the release architecture.

Release architecture

Same bug. Same team. Two release architectures.

App store path 5 days (illustrative)
  • 9:00Bug found in production
  • 9:20Fix reviewed and merged
  • 10:00Version bumped, binary built, submitted
  • Waiting in review
  • WedUsers finally get the fix
EAS Update path 30 minutes (illustrative)
  • 9:00Bug found in production
  • 9:20Fix reviewed and merged
  • 9:25Published to preview channel, verified
  • 9:30Published to production, partial rollout
  • 9:30Available to the rollout cohort; delivery and rollback timing vary by device

Only the release path differs. The fix, the developer, and the codebase are identical.

We build production mobile applications at Green Platform Solutions, and we've learned that the most expensive React Native decisions aren't necessarily the ones that affect today's feature. They're the ones that determine how difficult the application will be to build, release, and recover six months later.

EAS doesn't solve all of those problems. But where the team chooses to use it, it can remove a significant amount of infrastructure from the critical path.

This article is about recognizing those decisions early — before they become expensive constraints.

How Much Native Infrastructure Do You Want to Own?

The first major React Native decision is often framed as Expo vs. bare React Native. That framing is outdated.

The better question is: how much native infrastructure does your team want to own?

Owning it directly means maintaining Xcode settings and provisioning, Gradle configuration, CocoaPods, native dependencies, and their compatibility with your React Native version.

For some products, that's necessary: custom video pipelines, proprietary hardware, low-level audio, or deep OS integrations.

For others, Expo's tooling removes much of that maintenance. Development builds, config plugins, prebuild, and the Expo SDK let you use custom native code without manually maintaining every native project change.

The question isn't "could we need native control?" It's "if we own this layer, what do we stop building to maintain it?"

The common failure is taking on native ownership for optionality the team never uses. The opposite failure is equally real: relying on managed tooling when the product genuinely needs native control.

Navigation looks simple with three screens. It gets harder with nested stacks, modals, deep links, push notifications, and auth redirects.

The same applies to state. Local state is often the right starting point. The problem is adding global state reactively until values are scattered across Redux, Context, and components with no clear ownership model.

These decisions are cheap early and expensive to restructure later.

Dependencies are build-system decisions too

Adding a library feels harmless: storage, animations, permissions, media, analytics.

But in React Native, many dependencies aren't just JavaScript. Native dependencies become part of the iOS and Android build graph — and therefore part of your Xcode, Gradle, CocoaPods, and React Native compatibility surface.

Every native dependency is also a build-system dependency.

The goal isn't the fewest dependencies. It's fewer dependencies you later have to fight.

The Infrastructure You Postpone Until It’s Expensive

The common mistake isn't choosing the wrong tool. It's postponing the decision until changing it becomes expensive.

The API layer

Postponed as

Fetch calls inside components. They work, the data arrives, and the feature ships.

Expensive when

The same endpoint is used by several screens, each handling loading, errors, authentication, and retries differently.

A dedicated API layer gives you one place for network calls, authentication, error handling, caching, and retries.

Hours to build early. Weeks to retrofit across forty screens.

Authentication

Postponed as

A login screen that stores a token — which is the right place to start.

Expensive when

Token expiry, refresh, multiple user roles, and auth-driven navigation arrive later.

Production Auth Architecture Lifecycle
Secure Storage Token Lifecycle Refresh Handling Centralized Auth State 401 Interception Auth Navigation

For sensitive credentials, use platform-backed secure storage such as expo-secure-store rather than treating AsyncStorage as secure storage.

Environment management

Postponed as

One hardcoded API URL, because there is only one environment.

Expensive when

Staging appears, followed by environment-specific API keys, feature flags, logging, and credentials.

EAS gives you a cleaner separation:

ConcernWhere it lives
Build settingseas.json profiles
Secrets and variablesEAS environment variables (outside repository); client-bundled values are public
App configurationapp.json (consuming variables)

One particularly useful choice is giving staging and production different bundle identifiers. Both builds can then coexist on the same device instead of one overwriting the other.

Monitoring

Postponed as

Something to add after gaining users.

Expensive when

A production crash happens and the team has no stack trace, device context, or performance data.

Crash reporting turns “the app crashed” into actionable information. Performance monitoring reveals problems that may only appear on devices your team doesn't use.

The cost of adding observability late is the blindness that already happened.

The Release Process Is Part of Your Architecture

Teams treat releases as operations — adjacent to engineering rather than part of it. In mobile, that's wrong. How code reaches users constrains how a team can work.

Three EAS services cover three distinct stages, and the mental model is worth keeping:

Release Architecture

Three Services. Three Stages. One Continuous Model.

Stage 01 • Compilation

EAS Build

Creates the native binary in Expo's cloud infrastructure from your repository and build profiles.

Stage 02 • Distribution

EAS Submit

Automates store delivery to App Store Connect and Google Play using stored secure credentials.

Stage 03 • Continuous Fixes

EAS Update

Delivers compatible JavaScript bundles and assets to active binaries without review cycles.

Build and Submit govern the native binary shell. EAS Update creates a fast, independent second highway for the JavaScript layer.

Build

Producing a production iOS build used to be a ritual: the right Mac, matching Xcode version, correct provisioning profiles, and a matching CocoaPods environment. EAS Build moves compilation to Expo's cloud infrastructure, reducing build-infrastructure maintenance. The team still owns native configuration, dependencies, compatibility, and credentials. Windows developers can produce iOS builds, and new engineers ship code on day one without local toolchain struggles.

Submit

A release without automation is a person following remembered steps. Bump version, confirm branch, build locally, open App Store Connect, upload, enter notes, repeat for Google Play. eas submit uploads finished builds directly using stored credentials, transforming store distribution from a fragile manual ritual into a reproducible pipeline.

What EAS Update Actually Changes

A React Native app is two layers: a native binary, and a JavaScript bundle with its assets. The stores control distribution of the native binary. EAS Update distributes compatible JavaScript and assets to installed builds; native changes require a new binary.

EAS Update does not replace app-store releases. It creates a second release path for changes that are compatible with the installed native runtime.

EAS Update

One bundle. Compatible installed binaries on the configured channel and branch can receive it.

JS Bundle JavaScript + assets

EAS Update runtime-matched delivery

Rollout metrics

Android builds

iOS builds

Tablets

Users in the field

eas update:republish roll back to last good update • timing varies; no app review for a compatible update

The native binary stays where it is. Only compatible JavaScript and assets move — for installed builds on the configured channel and branch; native changes require a new binary.

How an update reaches a device

Update Lifecycle

How an Update Reaches a Device — The Five Controls

STAGE 01 Runtime Version Compatibility contract Fingerprint / version lock

STAGE 02 Channel Target baked into binary prod • preview • staging

STAGE 03 Branch Ordered update stream Channel mapping target

STAGE 04 Rollout Traffic canary split 10% → 50% → 100%

STAGE 05 Rollback Recovery without a new store review (timing varies) Minutes, no review

eas update:republish

Runtime versioning helps enforce compatibility. Staged rollouts and rollback reduce exposure, but recovery is not instant on every device and persistent-data changes can make rollback unsafe.

1. Runtime version — the compatibility contract.
Every build declares a runtimeVersion describing the JS-to-native interface it contains. An update is delivered only when runtime version and platform match exactly. Using the fingerprint runtime version policy derives this value directly from the native project, changing automatically whenever native code changes and reducing the chance of runtime mismatch crashes, though compatibility still depends on platform and configuration.

2. Channel — what a build points at.
Baked into the binary at build time via its eas.json profile (e.g., production, preview, staging). A binary points at exactly one channel.

3. Branch — the ordered list of updates.
A channel maps a build to a branch. You can repoint the channel's branch mapping without rebuilding binaries, subject to compatibility.

4. Rollout — who gets it first.
Updates can be served to a percentage of devices requesting it. Publish, expose to a fraction of traffic, monitor error rates, then widen.

5. Rollback — how you recover.
eas update:republish restores a previous update from branch history. If the update mechanism itself is compromised, rolling back to the bundle embedded in the binary returns clients to known-good state. The update path can avoid a new store review, but rollback is not immediate on every device and persistent-data changes can make it unsafe.

What it does to how a team works

When every change requires a review cycle, cadence drops, releases become high-stakes, and teams add heavy process to compensate. When correction is cheap, that pressure releases. The real value isn't deployment speed. It's that the cost of being wrong drops far enough to change how the team behaves.

What We Would Decide Differently Today

Having built and maintained several of these applications, some decisions we now make without debating:

  • We set up EAS Update before the first release, not after the first incident. Release strategy gets designed around fast correction rather than retrofitted onto slow processes.
  • We configure environments and build profiles on day one. Staging configuration never has to be untangled from application code conditionals later.
  • We decide the native ownership question explicitly and write down the reasoning. Not managed by default, not bare by default — a deliberate recorded trade-off.
  • We add crash reporting with the first production build. Every week without observability is a week of production behavior that cannot be reconstructed.
  • We default to the fingerprint runtime version policy. Deriving the compatibility hash from the native project eliminates human error.
  • We use partial rollouts on critical paths. A staged rollout converts a potential incident into a contained one at almost zero cost.

Frequently Asked Questions

Is Expo suitable for production applications?

Yes. Expo runs in production across major enterprises. Its SDK covers the native capabilities most production apps need, and development builds provide a supported path to custom native code whenever requirements call for it.

How should a team decide between Expo and bare React Native?

Frame it as ownership rather than capability. Teams with dedicated native engineers and genuine low-level hardware requirements may maintain their native projects directly. Teams building product features usually find that owning Xcode configuration and Gradle builds is an overhead without a matching benefit.

What is the difference between EAS Build, EAS Submit, and EAS Update?

ServiceWhat it doesWhen you need it
EAS BuildCreates native iOS and Android binaries in the cloudAny change to native code, dependencies, or app configuration
EAS SubmitDelivers binaries to App Store Connect and Google PlayEvery store release
EAS UpdateDelivers compatible JS and assets to installed binariesFixes and features that don't touch the native layer

When should CI/CD be introduced in a mobile project?

Before the first production release. Setting it up early avoids the high-pressure deadline crunch of building pipelines during an incident.

Final Thoughts

The goal was never to make every decision correctly at the start. The goal is narrower: recognize which decisions are expensive to reverse, make those deliberately, and choose infrastructure that leaves the rest open.

EAS Build reduces the build-infrastructure stack your team maintains, while the team still owns native configuration, dependencies, and compatibility. EAS Submit removes the manual ritual from releases. EAS Update creates a second release path for changes that fit the installed runtime — and lowers the cost of being wrong enough to change how a team operates.

None of that substitutes for engineering judgment. It just means the judgment goes toward decisions that actually require it.

Last updated: September 2026

Green Platform Solutions

Green Platform Solutions builds production mobile and web applications for businesses, with experience across React Native, Expo, cloud infrastructure, and application delivery. This article reflects problems encountered across multiple production projects and the decisions that made those projects easier or harder to maintain over time.

Ready to Transform Your Business with AI?

Get expert guidance on implementing AI solutions that actually work. Our team will help you design, build, and deploy custom automation tailored to your business needs.

  • Free 30-minute strategy session
  • Custom implementation roadmap
  • No commitment required