React Native App Release Pipeline for APAC Teams: A Step-by-Step Guide


Key Takeaways
- Define separate EAS build profiles per APAC market with region-specific signing and environment variables
- Automate iOS code signing with Fastlane Match to eliminate single-developer bottlenecks
- Use fail-fast: false in GitHub Actions matrices so one region's failure doesn't block others
- Target OTA updates to specific regional channels for precise hotfix delivery
- Enforce timezone-aware release gates to prevent off-hours submissions
Quick Answer: Set up per-region EAS build profiles, automate code signing with Fastlane Match, use GitHub Actions with a matrix strategy for parallel multi-market builds, and configure timezone-aware release gates to align deployments with your distributed APAC team's working hours.
Last year, a fintech client headquartered in Singapore asked us to ship a React Native payments app across five APAC markets — Hong Kong, Singapore, Vietnam, the Philippines, and Australia — within eight weeks. The app needed separate code-signing identities per market, localised store listings, and compliance with each country's data-residency requirements. Their existing pipeline was a single GitHub Actions workflow that one developer in Singapore triggered manually. Builds broke overnight (HK time), certificates expired without anyone noticing, and the Philippine QA team couldn't access TestFlight because the Apple Developer account was region-locked.
Related reading: OpenAI Valuation Funding AI Agent Economics: What APAC Enterprises Must Know About Vendor Lock-In
Related reading: JSON Data Pipeline Tooling Comparison: Modern Picks for APAC E-Commerce
Related reading: Task Scheduling Web Applications Serverless: When to Ditch Cron (and When Not To)
Related reading: AI Agent VPS Deployment Cost Optimization: A Practical APAC Playbook
This is the reality of building a React Native app release pipeline for APAC teams. The challenge isn't just CI/CD — it's orchestrating code signing, store submissions, time zones, and compliance across a distributed squad that spans UTC+7 to UTC+11.
This tutorial walks through the exact pipeline architecture our Branch8 engineering teams now use across HK, SG, VN, and PH. Every step includes copy-pasteable configuration. By the end, you'll have a working multi-region release pipeline that handles both iOS and Android builds, OTA updates via EAS, and automated store submissions — all governed by roles that respect your distributed team structure.
Prerequisites
Before starting, confirm you have the following in place:
Accounts and Access
- Apple Developer Program membership (USD 99/year per entity) — if you publish under separate legal entities per market, you need one per entity
- Google Play Console access with appropriate user roles per region
- Expo account (free tier works for evaluation; Production plan at USD 99/month recommended for teams above five developers, per Expo's 2024 pricing)
- GitHub repository with branch protection enabled on
mainandrelease/*branches - Fastlane installed locally (
brew install fastlaneon macOS)
Tooling Versions
- Node.js 20 LTS or later
- React Native 0.76+ (this tutorial uses 0.76.3)
- EAS CLI 13.x+ (
npm install -g eas-cli) - Fastlane 2.225+
- Xcode 16.x (for local iOS builds and certificate management)
Team Requirements
- At least one team member with Admin-level access to both Apple Developer Portal and Google Play Console
- A shared secrets management tool — we use 1Password for Teams and inject secrets via the
opCLI, though AWS Secrets Manager or HashiCorp Vault work equally well - Agreement on a branching strategy: this guide assumes trunk-based development with short-lived feature branches and
release/vX.Y.Zbranches for production cuts
Step 1: Configure EAS Build Profiles Per Region
The first piece of a React Native app release pipeline for APAC teams is build profiles that map to your target markets. EAS Build lets you define multiple profiles in eas.json, each with its own signing credentials, environment variables, and distribution settings.
Create or update eas.json at your project root:
1{2 "cli": {3 "version": ">= 13.0.0",4 "appVersionSource": "remote"5 },6 "build": {7 "development": {8 "developmentClient": true,9 "distribution": "internal",10 "ios": {11 "simulator": false12 },13 "env": {14 "APP_ENV": "development",15 "API_BASE_URL": "https://dev-api.example.com"16 }17 },18 "staging-apac": {19 "distribution": "internal",20 "channel": "staging-apac",21 "ios": {22 "buildConfiguration": "Release"23 },24 "android": {25 "buildType": "apk"26 },27 "env": {28 "APP_ENV": "staging",29 "API_BASE_URL": "https://staging-api.example.com",30 "REGION": "APAC"31 }32 },33 "production-sg": {34 "autoIncrement": true,35 "channel": "production-sg",36 "distribution": "store",37 "env": {38 "APP_ENV": "production",39 "API_BASE_URL": "https://api-sg.example.com",40 "REGION": "SG",41 "DATA_RESIDENCY": "ap-southeast-1"42 }43 },44 "production-hk": {45 "autoIncrement": true,46 "channel": "production-hk",47 "distribution": "store",48 "env": {49 "APP_ENV": "production",50 "API_BASE_URL": "https://api-hk.example.com",51 "REGION": "HK",52 "DATA_RESIDENCY": "ap-east-1"53 }54 },55 "production-au": {56 "autoIncrement": true,57 "channel": "production-au",58 "distribution": "store",59 "env": {60 "APP_ENV": "production",61 "API_BASE_URL": "https://api-au.example.com",62 "REGION": "AU",63 "DATA_RESIDENCY": "ap-southeast-2"64 }65 }66 },67 "submit": {68 "production-sg": {69 "ios": {70 "ascAppId": "1234567890",71 "appleTeamId": "TEAM_SG_ID"72 },73 "android": {74 "track": "production",75 "releaseStatus": "completed"76 }77 }78 }79}
Key design decisions here: each production profile maps to one market with its own API endpoint, data-residency flag, and EAS Update channel. This lets you push OTA updates to Singapore users without touching the Australian build. According to Expo's documentation, channels are the primary mechanism for routing updates to specific builds, so get this mapping right from day one.
Ready to Transform Your Ecommerce Operations?
Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.
Step 2: Manage Code Signing Across Distributed Teams
Code signing is where most APAC teams hit their first wall. When your iOS signing certificates live on one developer's MacBook in Ho Chi Minh City and your release manager is in Hong Kong, you have a coordination problem that no amount of Slack messages can fix.
iOS: Use Fastlane Match with a Private Git Repo
Fastlane Match stores encrypted signing certificates and provisioning profiles in a private Git repository, making them accessible to every authorised team member and CI runner.
Initialise Match:
1fastlane match init
Select git as storage mode and point it to a private repository (e.g., [email protected]:your-org/ios-certificates.git).
Then generate certificates for each environment:
1# Development certificates for internal testing2fastlane match development --app_identifier com.example.app.sg34# Distribution certificates for App Store submission5fastlane match appstore --app_identifier com.example.app.sg6fastlane match appstore --app_identifier com.example.app.hk7fastlane match appstore --app_identifier com.example.app.au
Your Matchfile should look like this:
1git_url("[email protected]:your-org/ios-certificates.git")2storage_mode("git")3type("appstore")4app_identifier(["com.example.app.sg", "com.example.app.hk", "com.example.app.au"])5username("[email protected]")6team_id("YOUR_APPLE_TEAM_ID")
Android: Centralise Your Keystore
For Android, generate one release keystore and store it encrypted in your secrets manager:
1keytool -genkeypair -v \2 -storetype PKCS12 \3 -keystore release.keystore \4 -alias app-release \5 -keyalg RSA \6 -keysize 2048 \7 -validity 10000 \8 -dname "CN=Example Corp, OU=Mobile, O=Example, L=Singapore, ST=SG, C=SG"
Store the keystore and its password in 1Password or your vault. Reference them in eas.json via EAS Secrets:
1eas secret:create --scope project --name ANDROID_KEYSTORE --type file --value ./release.keystore2eas secret:create --scope project --name ANDROID_KEYSTORE_PASSWORD --type string --value "your-password"3eas secret:create --scope project --name ANDROID_KEY_ALIAS --type string --value "app-release"4eas secret:create --scope project --name ANDROID_KEY_PASSWORD --type string --value "your-key-password"
A 2023 survey by JetBrains found that 63% of mobile developers use CI/CD pipelines, but only 29% automate code signing (JetBrains Developer Ecosystem Survey 2023). Automating signing from the start eliminates the single-point-of-failure problem that plagues distributed teams.
Step 3: Build the GitHub Actions Workflow
Here's where the pipeline comes together. Create .github/workflows/release-apac.yml:
1name: APAC Release Pipeline23on:4 push:5 branches:6 - 'release/v*'7 workflow_dispatch:8 inputs:9 region:10 description: 'Target region (sg, hk, au, all)'11 required: true12 default: 'all'13 type: choice14 options:15 - sg16 - hk17 - au18 - all19 platform:20 description: 'Platform (ios, android, all)'21 required: true22 default: 'all'23 type: choice24 options:25 - ios26 - android27 - all2829jobs:30 determine-matrix:31 runs-on: ubuntu-latest32 outputs:33 regions: ${{ steps.set-matrix.outputs.regions }}34 platforms: ${{ steps.set-matrix.outputs.platforms }}35 steps:36 - id: set-matrix37 run: |38 if [ "${{ inputs.region }}" = "all" ] || [ -z "${{ inputs.region }}" ]; then39 echo 'regions=["sg","hk","au"]' >> $GITHUB_OUTPUT40 else41 echo 'regions=["${{ inputs.region }}"]' >> $GITHUB_OUTPUT42 fi43 if [ "${{ inputs.platform }}" = "all" ] || [ -z "${{ inputs.platform }}" ]; then44 echo 'platforms=["ios","android"]' >> $GITHUB_OUTPUT45 else46 echo 'platforms=["${{ inputs.platform }}"]' >> $GITHUB_OUTPUT47 fi4849 build:50 needs: determine-matrix51 runs-on: ubuntu-latest52 strategy:53 matrix:54 region: ${{ fromJson(needs.determine-matrix.outputs.regions) }}55 platform: ${{ fromJson(needs.determine-matrix.outputs.platforms) }}56 fail-fast: false57 steps:58 - uses: actions/checkout@v45960 - uses: actions/setup-node@v461 with:62 node-version: 2063 cache: 'npm'6465 - run: npm ci6667 - uses: expo/expo-github-action@v868 with:69 eas-version: latest70 token: ${{ secrets.EXPO_TOKEN }}7172 - name: Run EAS Build73 run: |74 eas build \75 --profile production-${{ matrix.region }} \76 --platform ${{ matrix.platform }} \77 --non-interactive \78 --no-wait7980 submit:81 needs: build82 runs-on: ubuntu-latest83 if: github.ref_name != 'release/v*-rc*'84 strategy:85 matrix:86 region: ${{ fromJson(needs.determine-matrix.outputs.regions) }}87 steps:88 - uses: actions/checkout@v48990 - uses: expo/expo-github-action@v891 with:92 eas-version: latest93 token: ${{ secrets.EXPO_TOKEN }}9495 - name: Submit to stores96 run: |97 eas submit \98 --profile production-${{ matrix.region }} \99 --platform all \100 --non-interactive101102 notify:103 needs: [build, submit]104 runs-on: ubuntu-latest105 if: always()106 steps:107 - name: Slack notification108 uses: slackapi/slack-github-[email protected]109 with:110 payload: |111 {112 "channel": "#apac-releases",113 "text": "Release pipeline finished. Build: ${{ needs.build.result }}, Submit: ${{ needs.submit.result }}"114 }115 env:116 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Notice fail-fast: false on the build matrix. This is critical for APAC teams: if the Hong Kong build fails due to a certificate issue, you don't want it to cancel the Singapore and Australia builds that are perfectly fine. Each region should succeed or fail independently.
Ready to Transform Your Ecommerce Operations?
Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.
Step 4: Configure OTA Updates by Region
EAS Update lets you push JavaScript bundle changes without a full store submission — essential when you need to fix a critical bug during APAC business hours (UTC+8 to UTC+11) without waiting for App Store review, which Apple reports averages 24 hours but can stretch to 48 (Apple Developer Documentation, 2024).
Set up your update channels in eas.json (already done in Step 1), then create a dedicated workflow for OTA updates:
1# Push an OTA update to Singapore production users only2eas update --channel production-sg --message "Fix: payment gateway timeout for DBS bank"34# Push to all APAC regions5for region in sg hk au; do6 eas update --channel production-$region --message "Hotfix: locale date formatting"7done
For a GitHub Actions version, add this job to a separate workflow file .github/workflows/ota-update.yml:
1name: OTA Update (APAC)23on:4 workflow_dispatch:5 inputs:6 channel:7 description: 'Update channel (production-sg, production-hk, production-au)'8 required: true9 message:10 description: 'Update message'11 required: true1213jobs:14 update:15 runs-on: ubuntu-latest16 steps:17 - uses: actions/checkout@v418 - uses: actions/setup-node@v419 with:20 node-version: 2021 cache: 'npm'22 - run: npm ci23 - uses: expo/expo-github-action@v824 with:25 eas-version: latest26 token: ${{ secrets.EXPO_TOKEN }}27 - run: |28 eas update \29 --channel ${{ inputs.channel }} \30 --message "${{ inputs.message }}" \31 --non-interactive
Step 5: Handle Regional Store Submission Metadata
App Store Connect and Google Play both support localised store listings, but managing them manually across Traditional Chinese (HK/TW), Simplified Chinese (SG), Vietnamese, Filipino, and English (AU) is unsustainable.
Use Fastlane's deliver (iOS) and supply (Android) to automate metadata management. Create a directory structure:
1fastlane/metadata/2├── en-AU/3│ ├── description.txt4│ ├── keywords.txt5│ ├── release_notes.txt6│ └── subtitle.txt7├── zh-Hant/8│ ├── description.txt9│ ├── keywords.txt10│ ├── release_notes.txt11│ └── subtitle.txt12├── vi/13│ ├── description.txt14│ ├── keywords.txt15│ ├── release_notes.txt16│ └── subtitle.txt
Then in your Fastfile:
1platform :ios do2 desc "Upload metadata to App Store Connect"3 lane :upload_metadata do4 deliver(5 skip_binary_upload: true,6 skip_screenshots: true,7 force: true,8 metadata_path: "./fastlane/metadata",9 app_identifier: "com.example.app.sg",10 team_id: "YOUR_APPLE_TEAM_ID"11 )12 end13end1415platform :android do16 desc "Upload metadata to Google Play"17 lane :upload_metadata do18 supply(19 skip_upload_apk: true,20 skip_upload_aab: true,21 metadata_path: "./fastlane/metadata/android",22 json_key: "./google-play-service-account.json"23 )24 end25end
Google's own data shows that apps with localised store listings see up to 30% more installs per market compared to English-only listings (Google Play Console Help, 2024). For APAC markets where English proficiency varies significantly — from near-universal in Singapore to around 53% in Vietnam according to the EF English Proficiency Index 2024 — this isn't optional.
Ready to Transform Your Ecommerce Operations?
Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.
Step 6: Enforce Timezone-Aware Release Gates
One often-overlooked aspect of a React Native app release pipeline for APAC teams is timing. You don't want an automated pipeline to submit a production build to the App Store at 3 AM in your QA team's timezone.
Add a scheduling gate to your workflow:
1 pre-check:2 runs-on: ubuntu-latest3 outputs:4 should-proceed: ${{ steps.time-check.outputs.proceed }}5 steps:6 - id: time-check7 run: |8 # Get current hour in HKT (UTC+8)9 HOUR=$(TZ='Asia/Hong_Kong' date +%H)10 DAY=$(TZ='Asia/Hong_Kong' date +%u) # 1=Monday, 7=Sunday1112 # Only allow releases Mon-Thu, 10:00-17:00 HKT13 if [ "$DAY" -le 4 ] && [ "$HOUR" -ge 10 ] && [ "$HOUR" -lt 17 ]; then14 echo "proceed=true" >> $GITHUB_OUTPUT15 echo "Within release window (HKT)"16 else17 echo "proceed=false" >> $GITHUB_OUTPUT18 echo "Outside release window. Current HKT: $(TZ='Asia/Hong_Kong' date)"19 fi
We learned this the hard way. During the fintech project mentioned at the start, an auto-triggered build submitted to the Philippine App Store on a Friday evening Manila time. The review was rejected for a minor metadata issue, and nobody was available to fix it until Monday — losing the entire weekend's launch window. Since then, every production submission in our pipelines passes through a timezone gate.
Step 7: Set Up Role-Based Access for Multi-Country Teams
In a typical APAC setup, your team topology might look like this: engineering leads in Hong Kong or Singapore, QA in Vietnam or the Philippines, and product owners in Australia. Each role needs different pipeline permissions.
Create a CODEOWNERS file to enforce review requirements:
1# Release configurations require senior engineering approval2/eas.json @org/apac-engineering-leads3/fastlane/ @org/apac-engineering-leads4/.github/workflows/ @org/apac-engineering-leads56# Store metadata can be updated by product and localisation teams7/fastlane/metadata/ @org/apac-product @org/localisation89# App code requires standard review10/src/ @org/apac-engineers
Combine this with GitHub's environment protection rules. Create environments production-sg, production-hk, and production-au in your repository settings, each requiring approval from designated reviewers. According to GitHub's 2024 Octoverse report, teams using environment protection rules deploy 40% fewer rollback-worthy changes to production.
Ready to Transform Your Ecommerce Operations?
Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.
How We Run This at Branch8
When we built the pipeline described above for the Singapore fintech client, the setup took our HK-based platform team and VN-based mobile developers approximately three weeks — one week for EAS configuration and code signing automation, one week for the GitHub Actions workflows, and one week for testing across all five target markets.
The before-and-after difference was stark. Manual release cycles previously took 3-4 days per market, meaning a five-market release consumed nearly a month of elapsed time when you factor in sequential App Store reviews and timezone handoff delays. With the automated pipeline, we now ship to all five markets within 48 hours of cutting a release branch. The team uses EAS Update for OTA hotfixes roughly twice per sprint, with each update targeted to the specific channel that needs it.
We also moved away from Azure Pipelines for this specific project — not because Azure DevOps is lacking (it's excellent for enterprise workflows), but because EAS CLI's native integration with GitHub Actions eliminated an entire layer of custom build scripts that our VN team had been maintaining. The maintenance burden of those scripts was costing roughly 8 engineering hours per sprint.
Related reading: AI Agent VPS Deployment Cost Optimization: A Step-by-Step Playbook
What to Do Next
This pipeline covers builds, signing, submissions, and OTA updates. Here's where to extend it from Monday morning:
- Add automated E2E tests with Detox or Maestro — insert a testing job between the
buildandsubmitjobs in your GitHub Actions workflow. Maestro Cloud (acquired by mobile.dev in 2024) supports running tests against EAS builds directly. - Implement staged rollouts per region — Google Play supports percentage-based rollouts natively via
supply. Apple's phased release (7-day rollout) can be enabled in yourdeliverconfiguration. Start with 10% in one market before expanding. - Set up monitoring with Sentry or Datadog RUM — instrument your app with
@sentry/react-nativeand create per-region alerting rules. This closes the feedback loop: your pipeline ships, Sentry catches issues, and you push OTA fixes through the same channel system.
If your team is building a React Native app release pipeline for APAC teams and hitting walls around code signing, multi-region compliance, or simply the coordination overhead of distributed squads — reach out to Branch8. We've run this playbook across six APAC markets and can help you get from manual deploys to automated multi-region releases in under a month.
Ready to Transform Your Ecommerce Operations?
Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.
Sources
- Expo EAS Build Documentation: https://docs.expo.dev/build/introduction/
- Expo EAS Update Channels: https://docs.expo.dev/eas-update/how-it-works/
- Fastlane Match Documentation: https://docs.fastlane.tools/actions/match/
- JetBrains Developer Ecosystem Survey 2023: https://www.jetbrains.com/lp/devecosystem-2023/
- Google Play Console Localization Help: https://support.google.com/googleplay/android-developer/answer/9844778
- EF English Proficiency Index 2024: https://www.ef.com/epi/
- GitHub Octoverse 2024: https://github.blog/news-insights/octoverse/octoverse-2024/
- Apple App Review Times: https://developer.apple.com/app-store/review/
FAQ
Start by defining build profiles in eas.json for each target environment, automate code signing with Fastlane Match (iOS) and centralized keystores (Android), then create GitHub Actions workflows that trigger builds on release branch pushes. Use EAS Build for cloud builds and EAS Submit for automated store submissions.

About the Author
Elton Chan
Co-Founder, Second Talent & Branch8
Elton Chan is Co-Founder of Second Talent, a global tech hiring platform connecting companies with top-tier tech talent across Asia, ranked #1 in Global Hiring on G2 with a network of over 100,000 pre-vetted developers. He is also Co-Founder of Branch8, a Y Combinator-backed (S15) e-commerce technology firm headquartered in Hong Kong. With 14 years of experience spanning management consulting at Accenture (Dublin), cross-border e-commerce at Lazada Group (Singapore) under Rocket Internet, and enterprise platform delivery at Branch8, Elton brings a rare blend of strategy, technology, and operations expertise. He served as Founding Chairman of the Hong Kong E-Commerce Business Association (HKEBA), driving digital commerce education and cross-border collaboration across Asia. His work bridges technology, talent, and business strategy to help companies scale in an increasingly remote and digital world.