Skip to content
Guillaume Ojardias

Published on

Guillaume

From Backend to Mobile: How Expo (Almost) Turned Me Into a React Native Developer

A first-hand account of building Fusily, a mobile recipe app, as a backend developer — and how React Native + Expo made mobile development accessible.

Honesty first

I'm a backend developer. I've spent most of my career designing APIs, thinking in terms of databases, async workers, queues, and HTTP contracts. Frontend always felt like another world to me — not unreachable, but far enough from my habits that I never really made the leap. Mobile, even more so.

Then came the time to build Fusily.

Fusily is an app designed for cooking enthusiasts: sharing recipes, discovering new ones, planning meals for the week, generating a grocery list, and being guided step by step while actually cooking. A complete product, with a real user experience to craft, and a very concrete dimension — people use it with their hands literally in the dough.

Building this meant building a mobile app. And building a mobile app as a solo backend developer — or almost — meant making smart choices.


Why not pure native?

The first question, inevitable: Swift/Kotlin or cross-platform?

The honest answer is that pure native was simply not an option in my context. Learning Swift and Kotlin in parallel, maintaining two codebases, two release cycles, two test environments — that's a human and time investment that only makes sense for teams dedicated to each platform.

What I wanted was to write code once, deploy it on iOS and Android, without sacrificing the user experience. And if possible, build on skills I already had: JavaScript/TypeScript, asynchronous programming, a certain architectural rigor.

React Native answered that equation. Meta's framework lets you write components in JavaScript/TypeScript that compile to real native components — not dressed-up WebViews. Performance is solid, the community is huge, and the ecosystem is mature.

But React Native alone can quickly become a full-time configuration job. That's where Expo comes in.


Expo: the ecosystem that makes mobile accessible

Expo isn't just a build tool. It's a complete platform that covers the entire lifecycle of a mobile app, from the first npx create-expo-app all the way to publishing on the App Store and Google Play.

When I started Fusily, Expo's promise was simple: let you focus on your product, not on the plumbing. Coming from the backend world, where I'm used to spending time on infrastructure, that proposition felt genuinely refreshing.

Here's how it played out in practice.


Day-to-day development: Expo Go and dev builds

In the first weeks with Expo, you work with Expo Go — an app you install on your physical phone (or a simulator), which loads the app's JavaScript bundle over the local network. The feedback loop is immediate: you change a component, save, and the app updates on your device in seconds. It's the equivalent of the hot reload you know from web development, but in your pocket.

It's a great experience. But Expo Go has its limits: it doesn't support custom native modules. As soon as you step outside the officially supported library ecosystem — which happens pretty quickly on a real project — you need to switch to dev builds.

A dev build is a version of the app compiled with all its native dependencies, running an internal JavaScript development server. In practice, you generate it once via EAS Build (Expo's cloud build service), install it on your device, and get back most of the Expo Go experience — fast reloading — without its constraints.

For Fusily, the switch to dev builds came naturally, as soon as I started integrating features that touch the device's hardware.


The dependency ecosystem: Expo's real treasure

This is perhaps what surprised me most, and convinced me most. Expo maintains and distributes a set of libraries for accessing native device capabilities — all versioned, tested, and compatible with each other.

Here are some concrete examples of what I used in Fusily:

expo-haptics — Haptic feedback, those micro-vibrations that add texture to an interaction. In Fusily, when a user checks off a step in a recipe, a subtle haptic tap confirms the action. It seems like a small detail, but it's exactly this kind of thing that shapes how an app feels. Integrating it took me about ten minutes.

expo-secure-store — Secure storage, backed by iOS Keychain and its Android equivalent. I use this to persist authentication tokens safely, without going through AsyncStorage which writes in plain text. For a backend developer used to thinking in terms of data security, this is the expected behavior — and it's available with a three-line API.

expo-image-picker — Photo selection from the gallery or camera. In Fusily, users can attach a photo to their recipes. Handling permissions, opening the native picker, retrieving image metadata — all of it is cleanly encapsulated.

expo-file-system — Access to the device's file system. Useful for caching assets, managing temporary files, or implementing import/export features.

expo-notifications — Push notifications. I'll come back to this, but Expo handles device registration, token management, and notification reception through a unified iOS/Android abstraction.

What's structurally important about these libraries is that they are battle-tested in the real sense of the word: used by thousands of production apps, maintained by the Expo team, updated in a coordinated way with each new React Native release. When you're alone on a project, delegating this maintenance to a solid foundation is a sound strategic decision.


The build pipeline: dev, preview, production

Expo offers a cloud build service called EAS Build (Expo Application Services). It handles app compilation — a process that in pure native development requires Xcode for iOS and Android Studio for Android, with their own signing configurations, certificates, and provisioning profiles.

EAS Build abstracts away much of that complexity. Configuration lives in an eas.json file that defines the different build profiles:

Development — The dev build described above. Compiled with debug modules, connected to the local development server.

Preview — A near-production version of the app, distributable to internal testers via a direct link (no App Store or Play Store involved). In Fusily, I use this profile to validate features with a small group before publishing. EAS generates a QR code that testers scan to install the app directly — convenient.

Production — The final, optimized, signed build, ready for the stores. EAS can manage iOS certificates and Android keystores automatically if you want, or you can manage your own keys. The resulting binary is directly submittable to App Store Connect and Google Play Console.

What's comfortable about this model is that it's reproducible. Anyone on the project can trigger a build without having to configure their local environment from scratch. For someone coming from the backend world, used to CI/CD pipelines, this approach makes immediate sense.


Publishing to the stores: EAS Submit

Once the binaries are built, there's still the submission step. Apple and Google each have their own process — fairly tedious, with metadata configurations, screenshots at specific dimensions, descriptions, content classifications.

EAS Submit automates the technical part: uploading the binary to App Store Connect or Google Play using the configured credentials. The actual submission — Apple's review, Google's publication — remains manual through their respective interfaces, but the packaging work is handled.

My first App Store submission was rejected over a metadata issue (a permission description that wasn't explicit enough about photo access). That's the kind of friction you can't avoid, but EAS Submit at least ensures the technical side isn't an obstacle.


OTA Updates: shipping without going through the stores

This might be the feature that excited me most from a backend perspective.

EAS Update lets you publish JavaScript updates directly to users' devices, without submitting to the stores. The principle: the app loads its JavaScript bundle from Expo's servers at launch, and if a new version is available, it downloads and applies it on the next startup.

The limits are real — you can't modify native code this way, only JavaScript. But it covers a wide range of common cases: bug fixes, UI adjustments, small feature updates.

In Fusily, it fundamentally changes my relationship with deployment. A bug spotted in production can be fixed and shipped in minutes, without waiting for Apple's review cycle (which can take 24 to 48 hours). For a developer used to continuously deploying APIs, recovering that responsiveness on mobile is a real relief.

Configuration works through channels (production, preview, etc.) and branches, with a Git-like logic. You can route updates to subsets of users — useful for progressive rollouts.


Push Notifications: expo-notifications

Managing push notifications on mobile is notoriously complex. There are two different channels (APNs for iOS, FCM for Android), client-side permission handling, tokens to register and maintain on the server, and subtly different behaviors between platforms.

expo-notifications unifies all of this behind a common API. The flow is straightforward:

  1. Request permission from the user at the right moment in the experience
  2. Retrieve an Expo Push Token (a unique identifier per device, managed by Expo's servers)
  3. Register that token on your backend
  4. When you want to send a notification, call the Expo Push API with the token and payload

In Fusily, I use notifications to remind users of planned meals, or to let them know a new recipe in their area of interest has been shared. The trickiest part was handling permissions (the UX around the permission prompt is critical — asking too early kills the acceptance rate), not the technical implementation.


Looking back after a few months

I won't pretend Expo is perfect. There are moments of friction: SDK updates that require migrations, third-party libraries that don't yet support Expo Modules, subtle iOS/Android behavioral differences that only the native documentation can truly explain.

But stepping back on the overall experience — starting from zero, shipping Fusily on the App Store and Play Store, maintaining and evolving the app — Expo kept its core promise: letting me focus on the product.

As a backend developer, I was able to leverage my existing mental models (API design, async state management, data architecture) while learning a new rendering paradigm. React Native has its own idioms, its JavaScript/native bridge performance constraints, its layout subtleties — there's a real learning curve. But Expo's ecosystem significantly reduced the surface area of friction for everything that isn't the product code itself.

If you're a backend developer thinking about building a mobile app, my advice is simple: don't underestimate the React Native learning curve, but don't overestimate it either. And pick Expo. The time you won't spend configuring builds and maintaining native dependencies is time you can spend on what actually matters: your product.


Fusily is available on the App Store and Google Play. If you want to share recipes, plan your meals, or simply get more organized in the kitchen — come check it out.