---
title: "Expo app crashes on launch in TestFlight · Designated Dev"
description: "Why an Expo app that runs in Expo Go crashes the moment it opens in TestFlight, how to get the real error, and how to fix missing EAS environment variables."
url: "https://designateddev.com/guides/testflight-crash-on-launch-expo/"
---

1.  [Home](/)
2.  [Guides](/guides/)
3.  Diagnostics

Crash on launch

# Works in Expo Go, crashes on launch in TestFlight: how to find and fix it

Last verified September 27, 2026 by Designated Dev

## Short answer

The most common cause is environment variables that never reached the EAS build. EXPO\_PUBLIC\_ variables are inlined when the app is bundled, and a .env file that is gitignored is not uploaded to EAS Build, so values like your API URL are undefined in the binary and the app throws before its first screen. Other causes are native code Expo Go includes but your build doesn't, and errors that only appear in production mode.

> We will reject incomplete app bundles and binaries that crash or exhibit obvious technical problems.

[App Review Guideline 2.1(a), App Completeness](https://developer.apple.com/app-store/review/guidelines/)

## At a glance

| What you see | Why it happens | The fix |
| --- | --- | --- |
| Closes instantly on open, fine in Expo Go | EXPO_PUBLIC_ variables undefined: the .env was gitignored, so EAS Build never saw it | Store them as EAS environment variables and set environment in the eas.json build profile |
| Crashes when a feature using a native library opens | Expo Go ships that native code; your build lacks the library or its config plugin | Test on a development build; add the config plugin and rebuild |
| Works in development, fails only in release | Code that depends on development mode, or an error hidden by the dev server | Run npx expo start --no-dev --minify and fix the error it shows |
| Crashes when the camera, photos or location is first used | Missing usage description in Info.plist | Add the purpose string through app config or the library's config plugin |

## Why the preview hides this

Expo Go and a builder’s preview run your JavaScript inside an app that already exists, with its own native code and your local `.env` values available. A TestFlight build is a new binary, produced on EAS’s servers from what you uploaded. Anything that only existed on your machine, or only inside Expo Go, is missing.

It matters at review time too. In Apple’s 2025 App Store Transparency Report, Performance, the guideline category that covers crashes, accounted for 1,354,418 of the 2,093,244 rejected submissions.

## 1\. Get the real error first

Apple’s crash reports usually show a generic native abort, not the JavaScript error. Expo’s docs say it plainly: Apple’s crash reporting “does not include the exception message.” So reproduce it where you can read the log:

```
# A release build on your own simulator or device
npx expo run:ios --configuration Release

# JavaScript only: run the bundle in production mode
npx expo start --no-dev --minify
```

With the device connected, open **Console.app**, select the device and start streaming. The JavaScript error appears there when the app dies. TestFlight crash reports also appear in Xcode’s Crashes organizer and in App Store Connect under TestFlight feedback.

## 2\. The most common cause: environment variables that never reached EAS

Expo inlines `EXPO_PUBLIC_` variables into the bundle when it’s built. EAS Build decides what to upload from your `.gitignore` (or `.easignore`), so a `.env` file that is gitignored, as it usually is, never reaches the build server. In the binary, `process.env.EXPO_PUBLIC_API_URL` is simply `undefined`.

If a client such as Supabase or Firebase is created at import time with that value, it throws before the first screen renders. That is the classic instant crash.

The fix is to store the values as EAS environment variables and tell each build profile which environment to use:

```
eas env:set production --name EXPO_PUBLIC_API_URL --value https://api.example.com --visibility plaintext
```

```
{
  "build": {
    "preview": { "distribution": "internal", "environment": "preview" },
    "production": { "environment": "production" }
  }
}
```

Two rules from Expo’s docs are worth keeping in mind:

-   Read variables as `process.env.EXPO_PUBLIC_NAME`. Bracket access and destructuring are not inlined.
-   Anything prefixed `EXPO_PUBLIC_` ends up readable inside the app. Never put a secret key there. An OpenAI key, for example, belongs on a server.

Older tutorials use `eas secret:create`. The current commands are `eas env:set`, `eas env:list` and `eas env:pull`. Running `eas env:pull production` writes a matching `.env` locally, so your local release build behaves like the real one.

## 3\. Native code that Expo Go had and your build doesn’t

Expo Go ships a fixed set of native libraries and can’t run config plugins. A library can therefore “work” in Expo Go without ever having been set up for a real binary. Build a development build, test the feature there, and add the library’s config plugin if it needs one. `npx expo-doctor@latest` flags many of these mismatches.

From SDK 55, the New Architecture is always on and can’t be switched off. An older library that isn’t compatible can crash a release build even when the preview looked fine.

## 4\. Crashes on first use of the camera, photos or location

Apple’s documentation says that without the purpose string, attempts to access the resource fail “and might cause your app to crash.” Set the usage descriptions in your app config or through the library’s config plugin, and write each one as the real reason your app needs access.

## How we handle it

We rebuild the release binary locally, attach the device log, and fix the cause rather than the symptom: variables moved into EAS environments, secret keys moved behind a server, native libraries configured. Then we test the TestFlight build on a real device before it goes back to review.

## Questions

### Why does my app work in Expo Go but crash in TestFlight?

Most often because EXPO\_PUBLIC\_ variables from a gitignored .env file were never uploaded to EAS Build, so they are undefined in the binary. The next most common cause is native code that Expo Go bundles but your build does not include or configure.

### Are .env files uploaded to EAS Build?

Only if they are not excluded by .gitignore, or by .easignore if you have one. For cloud builds, store values as EAS environment variables and select them with the environment field in your eas.json build profile.

### How do I see why my TestFlight build crashed?

Crash reports appear in Xcode's Crashes organizer and in App Store Connect under TestFlight feedback. They usually lack the JavaScript error message, so reproduce with a local release build and read the device log in Console.app.

### What replaced eas secret:create?

The eas env commands. Use eas env:set to create or update a variable with a visibility of plaintext, sensitive or secret, and eas env:list to check what a build will receive.

### Will Apple reject an app that crashes on launch?

Yes. Guideline 2.1(a) says Apple will reject binaries that crash or show obvious technical problems, and asks you to test on a device for bugs and stability before submitting.

## Sources

1.  [Expo: Environment variables in Expo](https://docs.expo.dev/guides/environment-variables/)
2.  [Expo: EAS environment variables](https://docs.expo.dev/eas/environment-variables/)
3.  [Expo: Uploading files to EAS Build (.easignore)](https://docs.expo.dev/build-reference/easignore/)
4.  [Expo: Troubleshooting build errors and crashes](https://docs.expo.dev/build-reference/troubleshooting/)
5.  [Expo: Debugging runtime issues](https://docs.expo.dev/debugging/runtime-issues/)
6.  [Expo: Error recovery in EAS Update](https://docs.expo.dev/eas-update/error-recovery/)
7.  [Expo: EAS CLI reference](https://docs.expo.dev/eas/cli/)
8.  [Apple: Acquiring crash reports and diagnostic logs](https://developer.apple.com/documentation/xcode/acquiring-crash-reports-and-diagnostic-logs)
9.  [Apple: App Review Guidelines, 2.1](https://developer.apple.com/app-store/review/guidelines/)
10.  [Apple: 2025 App Store Transparency Report](https://www.apple.com/legal/app-store/transparency/2025/)

## Related guides

-   [Guideline 5.1.2(i)Rejected under 5.1.2(i)? How to add AI data consent to an Expo app](/guidelines/5-1-2-i-ai-data-consent/)
-   [RorkFixing a Rork app: what breaks between the preview and the App Store](/fix/rork/)
-   [Guideline 3.1.1Guideline 3.1.1 rejection: adding a working Restore Purchases to an Expo app with RevenueCat](/guidelines/3-1-1-restore-purchases/)

Stuck on this in your own app?

## We fix it, test it on real devices, and resubmit.

30 minutes with the engineer who'd do the work. Bring the repo link or the rejection email. Fixed price once scoped, in writing.

[Book a call](https://cal.com/designateddev/intro)[Or tell us what's broken](https://designateddev.com/guides/testflight-crash-on-launch-expo/#send)

[Designated Dev](/)

[What breaks](/#found)[Process](/#process)[Pricing](/#pricing)[Guides](/guides/)[FAQ](/#faq)[Privacy](/privacy/)

[hello@designateddev.com](mailto:hello@designateddev.com)Updated Sep 27, 2026Live on both stores
