A comprehensive guide to building beautiful mobile applications using Expo and React Native
Creating mobile applications has never been easier thanks to Expo and React Native. Whether you're a web developer looking to reach iOS and Android without learning Swift or Kotlin, or a product team that needs one codebase for two platforms, Expo provides the tooling, libraries, and deployment pipeline to ship fast and iterate with confidence. In this guide, we explore how to build beautiful, performant mobile apps with Expo, from initial setup to app store submission.
We'll cover project structure, navigation patterns, styling and theming, native modules when you need them, and best practices we've learned building production apps for our clients. By the end, you'll have a clear path from idea to published app.
Why Choose Expo?
Expo is more than a starter template. It's a complete development platform for React Native. It abstracts away much of the native tooling (Xcode, Android Studio, CocoaPods, Gradle) so you can focus on your app logic and UI. Here's what that means in practice.
Unified Development
Write once, deploy to iOS and Android. React Native gives you a single JavaScript (or TypeScript) codebase that renders to native views on each platform. Expo adds a consistent layer on top: one CLI, one config format, one way to add native capabilities. You don't need a Mac to develop for iOS (Expo Go and EAS Build handle that), and you don't need to touch Xcode or Android Studio until you're ready to customize native code.
This unification speeds up development and reduces bugs. Fix a bug once, it's fixed on both platforms. Add a feature once, it's available everywhere. Your team can stay in one repo and one mental model instead of maintaining two separate native codebases.
Over-the-Air Updates
Push updates to your app without going through the app store review process. With EAS Update, you can ship bug fixes, copy changes, and even small feature tweaks in minutes. Users get the update the next time they open the app (or immediately if you use the right update strategy). This is a game-changer for iteration speed and for fixing critical issues without waiting for Apple or Google.
There are limits: you can't change native code or add new native dependencies via OTA. But for JS/TS and asset changes, OTA updates keep your app fresh without the friction of store reviews.
Rich Ecosystem
Expo provides a curated set of modules for common native capabilities: camera, location, notifications, file system, secure store, and more. These modules are well documented, maintained, and designed to work across iOS and Android. When you need something that isn't in the Expo SDK, you can often find a community package or write a config plugin to integrate a native library without ejecting.
The ecosystem also includes EAS Build (cloud builds for iOS and Android), EAS Submit (submit to the app stores), and EAS Update. You get a single workflow from development to distribution.
Getting Started
Initialize your project with:
npx create-expo-app@latest
Choose a template (blank, tabs, etc.) and whether to use TypeScript. We recommend TypeScript for better code quality and editor support. Once the project is created, navigate into the directory and start the development server:
cd my-app
npx expo start
You'll see a QR code in the terminal. Scan it with the Expo Go app on your phone (iOS or Android) to run your app on a real device, or press i or a to open an iOS or Android simulator if you have one installed. Changes to your code will hot-reload in the app.
Project Structure and Navigation
A typical Expo app might look like this:
app/– File-based routing (if using Expo Router) or your main screenscomponents/– Reusable UI componentshooks/– Custom hooksconstants/– Colors, layout, configassets/– Images, fonts
If you use Expo Router, the app directory defines your routes: app/index.tsx is the home screen, app/settings.tsx is the settings screen, app/(tabs)/ might be a tab navigator. This pattern is similar to Next.js and keeps routing colocated with screens.
For navigation, Expo Router uses file-based routing by default. You can also use React Navigation directly if you prefer imperative navigation or a different structure. Either way, define your navigators (stack, tabs, drawer) once and use them consistently so deep linking and back behavior work as expected.
Styling and Theming
React Native uses a subset of CSS-like styles via the StyleSheet API. No class names. You pass style objects to components. Expo doesn't lock you into a styling approach; you can use plain StyleSheet, or add a library like NativeWind (Tailwind for React Native) or Tamagui for a design-system approach.
For theming (e.g. light/dark mode), use React context or a library like react-native-themed. Store colors, spacing, and typography in a theme object and consume it in your components. Respect the system appearance (useColorScheme()) so your app feels native.
Native Modules and Config Plugins
When you need a native capability that isn't in the Expo SDK, you have two main options. First, check if there's an Expo config plugin that wraps the native library. Many popular libraries (e.g. for maps, analytics, payments) have first-party or community plugins. Add the plugin to your app.json or app.config.js, run a prebuild if needed, and the native code is integrated without leaving the managed workflow.
Second, if no plugin exists, you can write a config plugin yourself (Expo's docs explain how) or use a development build with custom native code. EAS Build can produce these builds in the cloud, so you still don't need to install Xcode or Android Studio locally unless you're debugging native code.
Testing and Quality
Test on real devices early and often. Simulators are useful for quick iteration, but they don't catch all performance issues or platform quirks. Use EAS Build to produce development builds and install them on your team's devices, or use Expo Go for the majority of development and only move to dev builds when you need custom native code.
For automated testing, consider Jest for unit tests and Detox or Maestro for end-to-end tests. Lint with ESLint and type-check with TypeScript. Set up CI (e.g. GitHub Actions) to run tests and build on every PR so you catch regressions before release.
Deployment
When you're ready to ship, use EAS Build to produce production builds for iOS and Android. Configure your app identifier, version, and signing credentials in EAS (or link to your Apple and Google accounts). EAS Submit can then upload the builds to the App Store and Google Play, or you can download the artifacts and submit manually.
Before submitting, double-check store requirements: privacy policy, app icons, screenshots, and store listing copy. Both Apple and Google have review guidelines that can delay or reject your app if not followed. Plan for a few days to a week for first-time review; updates are often faster.
Conclusion
Expo makes mobile development accessible to web developers while maintaining native performance and capability. With a single codebase, over-the-air updates, and a clear path from development to app store, it's our preferred choice for client mobile projects at Realsync. Start with the basics we've covered here, explore the Expo documentation for advanced topics, and reach out if you need help architecting or building your next app.


