In expo-updates, what distinguishes isEmbeddedLaunch from isEmergencyLaunch, and what should an app do when each is true?
answer
- one is normal, one is a fallback
- embedded equals the bundle inside the binary
- emergency means startup failed
- emergencyLaunchReason carries the message
- both on Updates and currentlyRunning
basics
~20 sisEmbeddedLaunch is true when the running update is the one compiled into the binary, a normal state after install. isEmergencyLaunch is true when expo-updates hit an error at startup and fell back to the embedded bundle; log emergencyLaunchReason and tolerate older persisted data.
solid answer
~40 sBoth are constants on the `expo-updates` module and on `useUpdates().currentlyRunning`. `isEmbeddedLaunch` means the running update's ID equals the embedded update's ID: the app is on the bundle that shipped in the store binary, which is normal on a fresh install, before any update has downloaded, or after a rollback to embedded. `isEmergencyLaunch` means something failed while expo-updates was starting, such as reading its update storage, and it launched the embedded bundle as a last resort; `emergencyLaunchReason` holds the error message. The first needs no action beyond showing which build is running. The second deserves a log line with the reason, because the app may now be running code older than the data it saved under a newer update, so that code should read persisted state defensively.
go deeper
Recall that embedded means the bundle inside the store binary and that emergency means a start-up failure with a reason string.
List the normal situations that make isEmbeddedLaunch true, and explain that an emergency launch skips the updates database and runs the embedded bundle.
Wire emergencyLaunchReason into logging and make persisted-data readers tolerate a sudden step back to older code.
Treat embedded-bundle freshness as a policy input: how stale a store binary may get before a fallback becomes a user-visible regression.
## Two constants that sound alike **expo-updates** decides at every cold launch which **update** (a JavaScript bundle plus assets) to run. Two of its constants describe that choice, and interviewers use them to check whether a candidate knows the difference between a normal launch and a fallback: - **`isEmbeddedLaunch`**: `true` when the running update is the **embedded update**, the one compiled into the app binary at build time. - **`isEmergencyLaunch`**: `true` when expo-updates could not start normally and fell back to the embedded bundle as a last resort. **`emergencyLaunchReason`** then holds the error message. Both are exported from `expo-updates` (`Updates.isEmbeddedLaunch`, `Updates.isEmergencyLaunch`, `Updates.emergencyLaunchReason`) and are repeated on the `currentlyRunning` object returned by the `useUpdates()` hook. ## When isEmbeddedLaunch is true The native module computes it by comparing the ID of the launched update with the ID of the embedded one. It is `true` in ordinary situations: 1. The first launch after installing from the store, before any update has been downloaded. 2. Every launch while no compatible update has been published to the build's channel. 3. After the server sends a rollback directive and the client returns to the embedded update. 4. After error recovery falls back to an older working update and that update happens to be the embedded one. None of these is a fault. It is simply useful context, for example on a diagnostics screen next to `Updates.updateId` and `Updates.channel`. ## When isEmergencyLaunch is true An **emergency launch** happens when the start-up procedure itself fails: the loader task that reads the local updates database and picks an update throws, for instance because on-device storage could not be accessed. Instead of crashing, expo-updates launches the embedded bundle without its database. The source comment on the constant calls this rare and suggests using it to provide special behaviour when backwards compatibility matters. Why it matters: an emergency launch can put a device on code **older** than the update it ran yesterday. If yesterday's update migrated persisted data (a new cache format, renamed storage keys), today's older code must not crash when it reads that data. ## Do not infer one from the other | Question | Read this | |---|---| | Is the binary's own bundle running? | `isEmbeddedLaunch` | | Did expo-updates fail at startup? | `isEmergencyLaunch` and `emergencyLaunchReason` | | Is expo-updates active at all? | `isEnabled` | | Which update is it? | `updateId` (`null` when disabled) | `isEmbeddedLaunch` is derived from the launched update's ID, and on the emergency path expo-updates runs without its database, so do not treat `isEmbeddedLaunch` as a proxy for "something went wrong". Read `isEmergencyLaunch` for that. ## What to do in each case - **Embedded launch**: nothing special; show it in diagnostics so support can tell "never received the update" from "received it". - **Emergency launch**: report `emergencyLaunchReason` through your logging, keep reads of persisted data tolerant of newer formats, and avoid treating the launch as proof the latest update is broken, because the failure happened before any update code ran. - **Disabled** (`isEnabled` false, as in development): the embedded bundle runs and the JS update API rejects, which is expected rather than an emergency. ## Surfacing them in a build A small diagnostics screen, reachable from settings, is the usual home for these values. Read them once from `useUpdates().currentlyRunning` and render them as plain rows: the update ID, the channel, whether the launch was embedded, and the emergency reason when there is one. Support staff can then ask a user for one screenshot instead of guessing which code the device runs. Because the values are constants for the lifetime of a launch, there is no need to poll them; they change only after a reload or the next cold start. When `isEmergencyLaunch` is `true`, also consider skipping optional start-up work that depends on the newest data format, such as a background cache migration, until a normal launch returns. These constants are also different from **error recovery**, which reacts to a JavaScript crash inside a downloaded update; an emergency launch happens before any update's JavaScript runs.
- Why is an emergency launch a backwards-compatibility risk for persisted data?The fallback runs the embedded bundle, which can be older than the update the device ran last. If that newer update wrote data in a new shape, the older code reads a format it never knew. Keeping storage readers tolerant of unknown fields and versions lets the app survive until a normal launch returns.
- Is an emergency launch the same thing as error recovery after a crashing update?No. An emergency launch comes from a failure in expo-updates' own start-up, before any update's JavaScript runs. Error recovery reacts to a fatal JavaScript error thrown by a launched update and may fall back to an older working update or crash.
saying these in an interview costs you the question
- Treats isEmbeddedLaunch true as a sign the update system failed
- Thinks isEmergencyLaunch means the latest update's JavaScript crashed
- Uses isEmbeddedLaunch to detect emergencies instead of isEmergencyLaunch
- Assumes the embedded bundle is always newer than downloaded updates