Mobile app deployment is a crucial aspect of the development process. Automating this step can significantly enhance efficiency and control over an application’s build to deploy lifecycle. This article provides deployment options for a React Native app, identifies the best strategies, and discusses how to automate them. By integrating these approaches, we achieve the ability to deliver mobile app updates with the same speed as web app updates.
Both Google Play Store and Apple’s App Store have distinct criteria for publishing apps, making consistent cross-platform deployment automation challenging. And to keep up with the speed of agile development, there is clear need for streamlined, time-efficient deployment workflows.
Early in our mobile app development journey, we used Expo’s free tier for building and deploying apps. Although we could build the app on Expo and manually upload it to iOS and Android testing environments, this method introduced unpredictable wait times and limited control. Expo’s free tier provides 30 free builds each month (up to 15 for iOS) with EAS Build, but this limit can quickly be exhausted even in a limited sized project. The variability in build times for free plans—ranging from seconds to hours—poses a significant challenge, especially when dealing with high-severity or security issues that require immediate fixes.
While Expo offers a paid version for faster deployments, its added cost may not always fit within project budgets, especially for frequent deployments across multiple environments. Local builds can be an alternative, but they are repetitive and unavailable across development environment platforms (i.e. Mac vs. Windows), further complicating the process. These limitations pushed us to explore more cost-effective, reliable deployment solutions that wouldn’t compromise speed or quality, while keeping project spend in check.
To avoid the pitfalls of manual deployments, we identified several key requirements for automating our app deployment:
To address these deployment challenges, we implemented the following technologies:
For deciding the deployment workflow, our team wanted to make it very easy to access for both developers and testers, and using Expo was a straightforward answer to that requirement. There are alternatives like React Native CLI, a command line interface (CLI) tool created for the react-native package specifically.
The key difference between Expo and React Native CLI lies in their approach to the process of mobile app development. Expo offers a set of robust defaults and simplifies many aspects of app development, such as app permissions, push notifications, and dark mode. This allows developers to concentrate on crafting excellent user experiences without worrying about conflicts between third-party libraries, integration issues, upgrades, and maintenance.
On the other hand, React Native CLI provides more flexibility in selecting third-party libraries, which can be beneficial since Expo might limit certain app capabilities. However, this flexibility comes at the expense of additional developer time spent on integrating these libraries with native platforms. Consequently, while Expo’s native container is more constrained, it ensures stability across releases.
There are also some drawbacks to using Expo, such as:
When deciding on our deployment workflow, we initially found that Expo was more accessible for our developers. Expo simplifies many aspects of mobile development—app permissions, push notifications, and dark mode—allowing developers to focus on creating great user experiences without dealing with complex integrations. However, it does have its limitations.
Expo’s closed ecosystem, while stable, delays access to the latest iOS and Android updates. To address the need for more customization while retaining Expo’s benefits, we opted for Expo’s prebuild feature. This approach allows us to incorporate native customizations, similar to what’s possible with React Native CLI, but still within the Expo environment. While the React Native CLI offers extensive flexibility, Expo’s prebuild strikes a balance, enabling us to integrate native modules without requiring a full migration, making it a practical choice for high-quality app development.
One of the most valuable tools we use for automating app deployment is Fastlane, a widely adopted tool written in Ruby. Fastlane simplifies deployments across multiple environments (e.g., development, staging, production) by creating dedicated lanes for each platform. The Fastfile contains the deployment commands, and an auto-generated README.md helps all team members manage deployments consistently.
Fastlane integrates seamlessly with third-party services and allows us to automate app builds and submissions to the iOS App Store and Google Play Console, freeing up developers to focus on core tasks.
GitHub Actions provides an efficient platform for automating continuous integration and deployment (CI/CD) pipelines. Using YAML files, teams can define workflows for building, testing, and deploying applications. For React Native, we configured GitHub Actions to automate local builds for both iOS and Android environments.
By triggering workflows on code pushes or pull requests, our team can automate app builds and deployments without relying on external build services, ensuring faster and more flexible development cycles. This approach allows for more control over deployment timelines and mitigates dependency on cloud-based Expo services.
To manage deployment across multiple environments (development, staging, production), we implemented a strict Git branching strategy to prevent unintentional deployment of non-production builds. Each environment connects to its corresponding backend, so it's critical that only stable, production-ready builds are pushed to live environments.
We also adhere to Semantic Versioning (SemVer) to track app evolution, which uses a MAJOR.MINOR.PATCH structure:
For example, a build version like 1.2.0 indicates the first major release with two minor feature updates. A subsequent bug fix would bump this to 1.2.1.
When deploying across different environments:
By enforcing this versioning scheme, it’s easier to prevent accidental deployment of dev or staging builds to production environments. You can integrate version checks within CI/CD pipelines to further ensure that only production versions are pushed to app stores. Additionally, versioning helps rollback if an issue is discovered in a live environment, providing a clear history of the application’s changes.
In mobile app development, thorough testing of pre-release versions across both iOS and Android platforms is crucial to ensure a smooth user experience before the official launch. Managing beta testing, collecting feedback, and coordinating builds for various environments—such as development, staging, and production—can be challenging without the right tools. To streamline this process, we utilized Apple’s TestFlight for iOS and Google Play Console’s testing tracks for Android, allowing the team to focus on quality testing and feedback, rather than the complexities of distribution logistics.
TestFlight simplifies iOS beta testing by enabling developers to upload builds directly from Xcode to App Store Connect and distribute them to internal and external testers via email or public links. It also facilitates easy feedback collection, with testers able to submit crash logs, screenshots, and detailed reports. Multiple builds can be distributed simultaneously across development and staging environments, ensuring the isolation of non-production code from stable releases. TestFlight also automates the update process, allowing testers to always have the latest version with minimal manual involvement.
Similarly, Google Play Console’s internal, closed, and open testing tracks offer a robust solution for managing Android beta releases. Developers can upload APKs or AABs to specific testing tracks, inviting testers through email or public links, and gathering valuable feedback and crash reports. The flexibility to manage multiple testing tracks allows us to test different builds in isolation, ensuring that only stable, production-ready versions are promoted to the live store. Automatic updates keep testers on the most recent build, streamlining the feedback loop.
For Github Actions our Android and iOS pipelines will run the following steps:
Both pipelines allow for manual triggering through GitHub Actions, where users input version details such as new_version and, in the case of Android, also version_code. This ensures version control right from the start of the process.
The pipelines begin by setting up the necessary environment:
Configuration files (e.g., appConfig.ts, app.json) are updated in both pipelines to point to the appropriate environment (staging or production):
Both pipelines upload the generated app artifacts (APK, AAB, or IPA) to GitHub for future access:
After the build and deployment processes are complete:
This structure ensures a consistent and automated CI/CD workflow for both Android and iOS platforms, improving the efficiency of the development and release process while minimizing manual errors.
Once the pipelines do their magic and the QA team receives the app they are free to carry out tests as required before they release the app to the stores.
Automating the deployment and testing process for native mobile apps has proven to be a game-changer in delivering high-quality, fast, and secure updates. By leveraging tools like Expo, GitHub Actions, and Fastlane, we’ve been able to eliminate manual inefficiencies and reduce wait times, allowing us to deploy iOS and Android apps with the same speed and confidence as back-end updates. With a well-structured CI/CD pipeline in place, our team has adopted a "fail fast" strategy, ensuring that any issues are quickly identified and resolved, further enhancing our app's reliability.
Not only does automation improve deployment speeds and testing accuracy, it also ensures consistency across multiple environments, such as development, staging, and production. This leads to a smoother experience for both developers and end-users while reducing operational costs and risks associated with manual errors. Through the integration of multiple environments and proper versioning strategies, we safeguard against accidental deployment of non-production code to live environments.
By adopting these automation strategies, we at Perpetual have optimized our mobile app deployment and testing workflows, resulting in faster time-to-market, greater scalability, and enhanced security. This approach positions us and our customers to stay ahead in the competitive mobile app landscape, delivering high-performance apps with a streamlined and cost-effective deployment process.