Previous Why we chose Expo Application Services (EAS): A journey toward simplicity
Next Spotlight on Essenters: Tom Voigt - Jansen

Migration to Expo: The journey, the lessons, and where we stand today

Prashant Shrestha
7 minutes

MIGRATION TO EXPO: THE JOURNEY, THE LESSONS, AND WHERE WE STAND TODAY

If choosing Expo was a journey of discovery, migrating to Expo was a journey of patience, planning, and occasionally bribing CI pipelines with kind words (no proof this works, but it doesn’t hurt to try).

This is the story of how we carefully migrated production apps — without breaking our release schedule, blocking developers, or accidentally summoning new pipeline demons.

Our Starting Point: A Monorepo With… Personality

At the time of migration, our environment looked like this:
• Nx monorepo managed with npm
• Two separate React Native apps for two brands: Essent and Energiedirect
• Fastlane orchestrating everything from signing to submission
• GitLab CI pipelines handling daily builds
• Continuous delivery to alpha testers every single day
• Weekly production releases

Our challenge:
Migrate without disrupting any of this.
• daily alpha builds
• weekly production releases
• developer progress
• and the sanity of everyone involved
No pressure.

The migration goals (aka: our non-negotiables)

We aligned early on what “success” looked like:
• Move to Expo without breaking CI/CD
• Keep all core features functioning exactly the same
• Reuse our existing libraries whenever possible
• If a library didn’t support Expo, find an alternative OR write the missing integration
• Do NOT introduce delays in releases
• Do NOT freeze development
Basically:
Migrate the entire house… while still living inside it.


The challenges we thought we'd face (and the ones we didn’t expect)

We knew some things would be hard:
• library compatibility
• maintaining the monorepo
• migrating build scripts
• supporting two brands

But some challenges still managed to surprise us:
• libraries with deep native bridges not Expo-ready
• inconsistent Nx + npm + Expo support
• the need to build custom Expo plugins
• figuring out environment variable flow
• making sure developers didn’t need to relearn everything

Still, the biggest mountain was psychological:
Convincing ourselves that we could do this without blowing up CI/CD.

Our migration strategy (carefully controlled chaos)

We developed a step-by-step plan to avoid big-bang failures.

1. Setting up credentials & environment variables in Expo
We shifted all sensitive data — certificates, signing configs, environment variables — into Expo’s managed system.

2. Enabling SSO for our developers
Centralised access ensured the entire team could use EAS without manual account wrangling.

3. Creating new Expo apps inside the Monorepo
We built two new Expo apps (one for each brand) side-by-side with our existing React Native CLI apps.
This allowed:
• Incremental migration
• Zero disruption in existing CI/CD.
• Parallel development

4. Reusing code & libraries
Where libraries were compatible, we reused them directly.
Where they weren’t, we hunted for Expo-friendly replacements.

5. Designing new build pipelines
We created new build flows for:
• Development builds
• Alpha builds
• Production builds
These pipelines ran without touching the old ones — ensuring releases continued as usual.

6. Document everything
We produced documentation for:
• Onboarding and setup
• Development
• Build & deployment
• Common pitfalls

7. Knowledge sharing sessions
We ran onboarding session to get everyone up to speed quickly.

8. Cleanup phase
Only after Expo builds were stable did we begin decommissioning:
• old RN apps
• old pipelines
• macOS runners
• leftover scripts that didn’t serve purpose anymore
We’ll be honest—hitting “delete” on some of those old CI jobs felt liberating.

Fast-forward to today: Where we stand now

This is the part we’re proud of.
Migrating to Expo wasn’t a magic trick—there were headaches, late-night builds, and at least one developer questioning their life choices. But the dust has settled, and here’s the unvarnished picture of what we’ve built:

1. All apps are now Expo managed
We no longer have a Frankenstein of native iOS and Android projects.
All our apps are fully Expo managed, which means:
• One source of truth for builds
• No more chasing provisioning profiles like hidden treasure
• Centralized build logic for both brands

2. EAS build pipelines for development, alpha, and production
We now have dedicated pipelines for every stage:
• Development builds for daily work
• Alpha builds for QA testing
• Production builds ready for stores
Each pipeline is stable, predictable, and reproducible.
Gone are the days of the maintaining the macOS runners and their vulnerability issues.

3. Expo over-the-air updates
OTA is live—but cautiously.
• Development and Alpha channels only
• Allows testing bundle updates, asset loading, navigation, and JS-only patches without rebuilding
This way, we test before we break anything in front of actual users.
This ensures that when we enable OTA for production, we’ll be fully ready.

4. Reusable development builds
We can now generate a single dev build that works for:
• Multiple developers
• Feature reviewers
No more rebuilding for every branch or device.
This speeds up development and makes reviewing feature changes far less painful.

5. Stability through Expo managed config
A large part of our app configuration now lives in:
app.config.ts
eas.json

This gives us:
• Consistent environment setups across development, alpha, and production
• Config plugins that handle native code injection and platform-specific scripts
• The ability to include or exclude native behavior per build profile
• Centralized resource and asset management that simplifies handling icons, splash screens, permissions, and platform settings
It’s not magic — but it’s a much more controlled, predictable way to manage app configuration without juggling scattered native files.

6. Faster release cycles
With the EAS + Fastlane hybrid:
• Uploading to TestFlight and Play Store is smoother
• Promotional builds and internal testing flows are less stressful
• Weekly production releases are faster and more reliable
• Emergency fixes can go out immediately through OTA in dev/alpha channels
In short: we spend more time building features, less time babysitting builds, and the process actually makes sense now.

Limitations & challenges (The honest section)

Let’s talk openly. Expo is great… but not magic.

1. Limited support with Nx + npm + Expo
Expo + Nx + npm presented some tricky challenges:
• package dependencies and lock file needed careful synchronisation to generate consistent fingerprints
• CI/CD builds occasionally failed due to inconsistent resolutions
Our solution: migrate from npm to pnpm workspaces.
This allowed deterministic dependency resolution, consistent build fingerprints, and faster installs across developers.
The perfect example of “sometimes the small tooling choices make the biggest difference.”

2. Missing EAS features for store review submissions
EAS cannot (yet) fully replace Fastlane for auto-submitting new releases for review. So Fastlane still plays a small role in our release process.

3. Native widgets still require native projects
Our iOS & Android widgets, and some native modules, require direct platform code.
Expo supports them through config plugins, which we had to maintain for seamless builds.

4. Some native packages aren’t Expo-compatible
Certain libraries with native bridges required us to create custom Expo plugins:
• plist patches
• manifest entries
• Gradle modifications
• native code injections
It took effort, but now these packages integrate cleanly with EAS.

Final thoughts — Why Expo was the right choice

Migrating to Expo had some challenges, but it also brought relief to our mobile developers… and our build servers. Today, our setup is simpler, safer, and more predictable.
We’re continuing to find ways to improve, optimise our pipelines, and enhance the developer experience by planning our future improvements and roadmaps:
• Gradual rollout of OTA to production with monitoring with fully automated multi-channel releases
• Faster hotfixes and emergency releases
• Shared dev builds across feature teams
• Quicker reviewing and testing process with OTA updates on our development phase
• Expanding our internal custom plugins library and widget plugins
With Expo integrated, our team is now far more focused on building features, improving our apps, and shipping them faster to users—rather than wrestling with infrastructure.

Prashant Shrestha

As Senior Mobile Engineer on the Mobile Platform team at Essent IT, Prashant specializes in iOS, Android, and React Native. He enjoys collaborating with teams, tackling challenges, and taking responsibility for developing and building mobile solutions that deliver a seamless experience for our users, all while exploring new technologies along the way.