Skip to main content

Command Palette

Search for a command to run...

Reusable React Native Builds and Uploads with GitHub Actions and Fastlane

Updated
6 min readView as Markdown

A request for an installable app soon raises further questions: which environment does it use, how does another app join the pipeline, can an upload failure reuse the existing build, and can another engineer repeat the process?

I helped implement and maintain a shared GitHub Actions and Fastlane pipeline covering builds, artifact transfer, and uploads. Here, submission means uploading to TestFlight or a configured Google Play track. Formal review submission, review monitoring, and rollout control are a separate release orchestration design, not a completed end-to-end implementation.

Separate three configuration dimensions

Dimension Question Examples
Application environment Which business services does the app use? Test, production
Build and export type Which native artifact is produced? iOS device or simulator app; Android APK or AAB
Upload destination Where does the artifact go? Internal distribution, TestFlight, Google Play, build only

A production-connected iOS build can be distributed through TestFlight before public release. A simulator app is not a device artifact for store upload.

The shared entry point validates the platform and profile combination before choosing the execution lane. Callers provide an explicit delivery target while platform implementations remain independently maintainable.

Keep application policy separate from shared execution

Keep application policy separate from shared execution

Technical flow; implementation and validation boundaries are explained below.

My work included organizing application onboarding around stable metadata, signing configuration, and limited application hooks. Shared execution handles preparation, native builds, and artifact transfer; hooks own application-specific version and runtime rules.

Frequently changing build numbers do not belong in stable application metadata. Resolved iOS build numbers, Android version codes, and runtime identifiers travel through build metadata to the upload stage.

The upload identity must describe the artifact actually being uploaded. Recomputing a next build number during recovery can make the reported version differ from the binary.

Make the build-to-upload handoff explicit

Express the handoff through a fixed artifact identity

This iOS fragment omits dependency setup, signing, compilation and the upload lane. It keeps the existing build/post split and additionally illustrates artifact-ID binding and checksums; those additions are examples, not a claim about deployed behavior. Android can apply the same contract in its own build job.

# Handoff fragment for an iOS build. Project setup/build steps are omitted.
jobs:
  build:
    runs-on: macos-latest
    outputs:
      artifact_id: ${{ steps.archive.outputs.artifact-id }}
    steps:
      # Existing build steps must produce both files below.
      - name: Verify and fingerprint delivery
        run: |
          test -s delivery/app.ipa
          test -s delivery/build-info.json
          cd delivery
          shasum -a 256 app.ipa build-info.json > SHA256SUMS
      - uses: actions/upload-artifact@v7
        id: archive
        with:
          name: ios-${{ github.run_id }}-${{ github.run_attempt }}
          path: delivery/
          if-no-files-found: error
          retention-days: 14

  post:
    needs: build
    runs-on: macos-latest
    steps:
      - uses: actions/download-artifact@v8
        with:
          artifact-ids: ${{ needs.build.outputs.artifact_id }}
          path: delivery/
      - name: Verify before upload
        run: |
          cd delivery
          shasum -a 256 -c SHA256SUMS
      # Restore pinned tooling/configuration, then run the existing upload lane.
      # Read version/build identity from build-info.json; do not allocate it again.

The build producing the binary must also produce build-info.json, recording the actual source SHA, Bundle ID, build number, runtime and configuration revision. The artifact ID fixes the handoff object for this run. Checksums check file consistency, not signing identity, review status or trusted provenance. Cross-run recovery also requires the run ID, artifact ID, authorization context and a check for prior store receipt.

The example's 14-day retention illustrates a configurable recovery window; the inspected implementation uses one day. Longer review cycles still need separate archival. Inputs and outputs are defined by upload-artifact and download-artifact.

The existing pipeline separates build and post jobs. The first preserves native output and diagnostic material; the second restores its environment, downloads artifacts from that run, and executes upload and distribution steps.

This supports recovering the upload stage, provided artifacts remain available, metadata matches, and the destination has not already accepted the build. Two jobs alone do not establish unconditional retry safety.

A useful handoff records the application, source commit, configuration revision, platform, build identifiers, artifact location, destination track, and failure stage. It does not include secret values.

After an upload timeout, I would inspect the destination before retrying. A compiler failure requires correcting the source or toolchain and rebuilding. Those failures need different recovery actions.

Preserve platform-specific behavior

On iOS, the Team, Bundle ID, signing material, and entitlements must agree. The implemented upload lane loads build metadata, checks the IPA, and uploads to TestFlight.

An accepted upload, completed build processing, tester availability, and App Review approval are distinct. A lane configured not to wait for processing can finish before testers can install. Formal review requires selecting a build and completing the submission information. Apple submission documentation.

On Android, the lane resolves the package and track and checks for an AAB or APK. It distinguishes a draft-app path from ordinary uploads. A completed internal-track release is not a public production launch. First-time application setup also extends beyond what an upload tool does. Fastlane Google Play upload documentation.

Deliver diagnostic material with the binary

The pipeline includes artifact paths and upload logic for debugging material. Whether sourcemaps, symbols, or obfuscation mappings are enabled and successfully delivered must be checked for each application and run.

These files must match the build they describe. A green workflow does not prove every optional upload executed, and a mapping from another build cannot establish reliable source attribution.

The inspected build artifacts have a one-day retention period. That supports short-term transfer but does not cover a multi-day review lifecycle. Durable release storage belongs to the next phase of the design.

Scope a remote delivery engagement

I start by identifying the repository, platform, environment, signing setup, destination, and failing stage. The deliverables are a repeatable entry point, configuration instructions, the identified artifact and actual upload status, any device verification performed, and stage-specific recovery notes.

This article was checked against the application caller, shared workflows, actions, and upload lanes. No new hosted build or store upload was triggered for the article. Source inspection does not prove every application or branch has passed, and no unmeasured speed or labor savings are claimed.


ivan provides part-time remote support for React Native / iOS / Android builds, signing, and upload workflows through written, asynchronous collaboration.

Work with me

More from this blog

I

ivan — Mobile Engineering Notes

7 posts

Practical case studies on React Native, Expo upgrades, iOS native debugging, mobile CI/CD, and Maestro E2E. I share code, diagrams, and validation notes from implementation work, with design proposals clearly labeled. Written by ivan, available for part-time technical support through written, asynchronous collaboration.