E-NO
Expo production 7 Min Read

Expo Production Operations Checklist with Practical Examples

calendar_today Published: 2026-08-19
update Last Updated: 2026-08-19
analytics SEO Efficiency: 100%
Technical guide illustration for Expo Production Operations Checklist with Practical Examples.

Introduction

Running Expo apps in production requires more than a successful build. It demands a disciplined approach to observing the current state, making minimal changes, and verifying results. This checklist gives you a structured way to handle common operational tasks—from checking the installed Expo SDK version to recovering from a failed OTA update—with concrete commands and expected outputs.

This guide is written for developers, DevOps engineers, and technical leads who manage Expo applications in production. It assumes you have access to a terminal, the Expo CLI, and the ability to deploy updates via EAS (Expo Application Services).

We focus on operational safety: observe before you change, limit the blast radius of any modification, protect secrets, and always have a tested recovery path. Each section follows a consistent pattern: component, version, prerequisites, observation, change, verification, and recovery.

Version and Environment Inventory

Before you touch anything, know what you're working with. Accurate version and environment data prevents misapplied commands and helps you choose the right troubleshooting steps.

Identify the Installed SDK Version

Your first task is to determine the exact Expo SDK version running in your production app. This affects which commands and configuration options are available. Use a read-only command from the Expo CLI:

expo --version

Expected output (example):

6.3.10

This tells you the Expo CLI version, but you also need the SDK version from your project's package.json:

cat package.json | grep '"expo"'

Expected output (example):

"expo": "~51.0.0",

Now you know you're on SDK 51. This is your baseline. Record this in your runbook with a timestamp. If you need to debug a build or runtime issue, you'll thank yourself later.

Map Your Deployment Topology

Next, determine how your app is distributed. Are you using EAS Build? EAS Update? Both? Check your eas.json file:

cat eas.json

Expected output (example):

{
  "cli": {
    "version": ">= 5.0.0"
  },
  "build": {
    "production": {
      "channel": "production"
    }
  },
  "submit": {
    "production": {}
  }
}

This tells you that production builds use the 'production' channel. Now check your app's runtime version and channel via EAS:

eas channel:list

Expected output (example):

channel: production
appVersion: 1.2.0
runtimeVersion: 1.2.0

If you have multiple environments (staging, production), note them. This topology helps you scope changes and understand the blast radius.

Capturing Current State Safely

Always take a snapshot of the current state before making changes. For example, if you plan to update a configuration file, copy it first:

cp app.json app.json.bak.$(date +%Y%m%d%H%M%S)

This creates a timestamped backup, so you can always revert. Similarly, record the current EAS update history:

eas update:list --platform android --limit 1

Expected output (example):

ID: 12345678-1234-1234-1234-123456789abc
Group ID: 87654321-4321-4321-4321-543210fedcba
Update Runtime Version: 1.2.0
Created: 2025-04-03T10:00:00.000Z

Store these outputs in your incident log. They give you a baseline for comparison.

Protecting Secrets

Never include real API keys, tokens, or production identifiers in commands or logs. Use environment variables or placeholders. For instance, when running EAS commands, use $EAS_TOKEN instead of hardcoding:

EAS_TOKEN=your_token_here eas whoami

But even better, export the token from your CI/CD secret store. In a local terminal, use a shell prompt:

read -s -p "Enter EAS token: " EAS_TOKEN
echo
echo "Token acquired (length: ${#EAS_TOKEN})"

Now you can safely use $EAS_TOKEN in subsequent commands.

Safe Configuration Path

Configuration changes in production can have immediate impact. Follow this safe path to minimize risk.

Prerequisites for Configuration Changes

Before editing app.json or eas.json, verify that you have the correct CLI version and that you're logged in to EAS:

expo whoami

Expected output:

You are logged in as [email protected]

If you're not logged in, run expo login. Also verify that your local project matches the production branch:

git status --short

Expected output: clean working tree (no output implies clean).

Making a Small, Focused Change

Suppose you need to change the app's display name in app.json from MyApp to My App Pro. Make the smallest edit possible:

{
  "expo": {
    "name": "My App Pro",
    "slug": "my-app",
    ...
  }
}

After the edit, validate the JSON syntax:

python -m json.tool app.json > /dev/null && echo "JSON valid"

Expected output:

JSON valid

Verification and Rollback

After a change, verify that the app still passes basic health checks. If you use EAS Update, you can create a preview update on a test channel first:

eas update:configure --channel preview
eas update --channel preview --message "Test config change" --auto

Then install the preview build on a device and check that the settings apply. If all looks well, mirror the change to the production channel.

If something breaks, you can roll back by reverting to your backup file:

cp app.json.bak.20250404120000 app.json

Then redeploy the previous update. This is why we keep backups with timestamps.

Verification and Diagnostics

Even with careful configuration, issues arise. This section covers how to diagnose them systematically.

Health Check Commands

Start with a basic health check of your app's runtime. Use the Expo CLI to pull logs from a connected device or emulator:

expo start --dev-client

In another terminal, view logs:

adb logcat | grep -i expo

Expected output (if healthy):

I/ReactNativeJS: Running "main"

Checking OTA Update Status

If users report stale content, check the current update that's active on a device:

eas update:list --platform ios --limit 1 --channel production

Expected output (example):

ID: 12345678-1234-1234-1234-123456789abc
Group ID: 87654321-4321-4321-4321-543210fedcba
Update Runtime Version: 1.2.0
Created: 2025-04-02T15:30:00.000Z

Compare the Created timestamp with when the issue was reported. If the update is older than expected, users may have missed the latest release. If it's the latest, the problem may lie elsewhere.

Network and API Diagnostics

If your app depends on a backend, test connectivity from the device's perspective. Using a package like react-native-debugger or just a console.log in development can show network failures. In production, enable remote logging to a service like Sentry or LogRocket. For example, with Sentry:

import * as Sentry from 'sentry-expo';
Sentry.init({
  dsn: 'https://[email protected]/your-project-id',
  enableInExpoDevelopment: true,
});

When a network error occurs, Sentry logs it with stack trace. To check if the API endpoint is reachable, use a network tool from a terminal:

curl -I https://api.yourbackend.com/health

Expected output:

HTTP/1.1 200 OK

If you get a 500, backend issue. If you get a timeout, network/firewall issue. Record these findings.

Performance Checks

Use expo-dev-menu to enable performance monitoring. In development, open the dev menu and select “Performance Monitor”. This shows FPS, memory, and CPU usage. For production, integrate with react-native-performance:

import { initializePerformance } from 'react-native-performance';
initializePerformance();

Then log durations:

const perf = measurePerformance('myOperation');
// ... operation
const result = perf.stop();
console.log(`Operation took ${result.duration}ms`);

Use this data to identify jank or memory leaks.

Failure Modes and Recovery

Let's examine common failure scenarios and their remedies.

Failed OTA Update

Symptom: Users are stuck on an older version, or the app crashes on launch after an update.

Diagnosis: Check the update history for the failing update ID:

eas update:list --platform android --limit 5 --channel production

Expected output: list of recent updates with status. If an update has status: failed, it never became active. If it's active but crashing, you need a rollback.

Recovery: Force users back to the last known good update by creating a new update that reverts the problematic changes. Or, if your app supports incremental updates, you can use eas update:rollback (if configured).

eas update:rollback --channel production --target 12345678-1234-1234-1234-123456789abc

Verification: After rollback, check that the active update ID equals the target. Ask a few beta testers to confirm the crash is gone.

Environment Variable Lost

Symptom: App behaves differently in production, missing API keys.

Diagnosis: Verify that environment variables are present in the build configuration. For EAS Build, variables are injected at build time. Check your eas.json:

{
  "build": {
    "production": {
      "env": {
        "API_URL": "https://api.example.com"
      }
    }
  }
}

If the variable is missing, add it and rebuild.

Recovery: If you can't rebuild immediately, you can use EAS Update to provide a fallback value at runtime. In your app, read from process.env.API_URL with a fallback:

const API_URL = process.env.API_URL || 'https://default.example.com';

Verification: On a device, open the app and check that it logs the correct API URL. You can add a temporary console.log.

Certificate Expiry

Symptom: App Store/Play Store submission fails or app uninstalled after expiring certificate.

Diagnosis: Check certificate expiry dates via EAS credentials:

eas credentials --platform ios

Expected output includes distribution certificate info with expiry date. Similarly for Android:

eas credentials --platform android

Recovery: Renew the certificate. For iOS, create a new distribution certificate in Apple Developer portal and upload it to EAS:

eas credentials --platform ios --cert-upload

Follow the prompts. Then rebuild your app with the new certificate.

Verification: After rebuilding, check that the new certificate is active:

eas credentials --platform ios

Confirm the expiry date is updated.

Operations Checklist

Here's a consolidated checklist for every production change you make. Use this as a template for your runbooks.

1. Observe Before Changing

  • [ ] Record the current version of the component (Expo SDK, CLI, EAS CLI).
  • [ ] Check the current deployment topology (channels, runtime versions).
  • [ ] Capture a snapshot of configuration files (backup with timestamp).
  • [ ] Verify you have the necessary credentials (EAS login, tokens).

2. Scope the Change

  • [ ] Define the smallest change needed to achieve the goal.
  • [ ] List all affected files and services.
  • [ ] Assess the blast radius (what will this affect if it fails?).
  • [ ] Ensure you have a rollback plan.

3. Implement the Change

  • [ ] Apply the change exactly as scoped.
  • [ ] Use placeholders for any secrets.
  • [ ] Validate syntax (e.g., python -m json.tool for JSON).
  • [ ] If possible, test on a preview channel first.

4. Verify the Outcome

  • [ ] Run the command that confirms the expected state.
  • [ ] Compare the actual output with the expected output.
  • [ ] Check logs for any new errors.
  • [ ] Get a second person to review if the change is high-risk.

5. Document and Recover

  • [ ] Record what you did, when, and why.
  • [ ] Store the rollback command in your incident log.
  • [ ] If verification fails, execute the recovery plan immediately.
  • [ ] After recovery, document the incident and lessons learned.

Example Runbook: Changing the App's Splash Screen

Let's illustrate with a concrete example. You need to update the splash screen image for production.

Component: app.json -> expo.splash Prerequisite: Have the new image in assets/.

Observation:

cat app.json | grep -A 4 "splash"

Change: In app.json, modify the image path:

"splash": {
  "image": "./assets/splash-new.png",
  "resizeMode": "contain",
  "backgroundColor": "#ffffff"
}

Verification:

python -m json.tool app.json > /dev/null && echo "JSON valid"
eas update --channel production --message "Update splash screen" --auto

This pushes a new update. Use eas update:list to confirm the new update is active.

Recovery: If the splash screen is incorrect, revert by restoring the backup:

cp app.json.bak.* app.json

Then push another update.

Conclusion

A production operations checklist is only useful when every action is version-scoped, observable, and reversible. Blindly copying commands without understanding prerequisites and expected outputs can cause more harm than good.

Start small: pick one low-risk production task, such as verifying your Expo SDK version or listing your EAS channels. Record the current state, run the documented check, and compare the result with the expected signal. Then, gradually incorporate the full checklist into your deployment and incident response processes.

A reliable operational workflow makes failures visible early, protects sensitive credentials, limits changes to the intended resource, and defines recovery steps before a crisis forces a hasty decision. Use this checklist as your foundation, and adapt it to your organization's specific stack and risk tolerance.

Related Research

Article Quality Score

Reader usefulness 100%
  • check_circle Reader-ready guide
  • check_circle Practical examples included
  • check_circle Clean SEO article URL