React Native Roadmap 2026-W30
Week of July 20–July 26, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | Install dev and production side by side with app variants | 🟧 EXPO | Read |
| 2 | How Posh went from manual weekly mobile releases to continuous delivery with Expo | 🟧 EXPO | Read |
| 3 | From Expo Router to Detour: Deferred deep linking the right way | 🟧 EXPO | Read |
| 4 | EAS Observe moves to general availability on August 20 | 🟧 EXPO | Read |
| 5 | React 19.2.8 / 19.1.9 / 19.0.8 Released — DoS security fix | ⚛️ REACT | Read |
| 6 | shadcn/ui Adds React Aria as a Component Base | ⚛️ REACT | Read |
| 7 | Maestro MCP: Let Your Agent Use the App It Just Built | 🟦 RN | Read |
5-Day Action Plan
🟧 Chunk 1 — Configure Expo App Variants for Dev and Production Side by Side
Goal: Allow developers and testers to have both the development and production builds installed simultaneously on the same device, eliminating the need to uninstall and reinstall when switching environments.
Scope:
- Convert
app.jsontoapp.config.jsto enable dynamic configuration - Read
EXPO_PUBLIC_APP_VARIANTenvironment variable to switch betweendevelopmentandproduction - Assign a unique
bundleIdentifier/android.packageper variant (e.g.com.myapp.dev) - Give each variant a distinct display name (e.g. "MyApp (Dev)") and icon with a visual marker
- Update
eas.jsonbuild profiles to inject the correctEXPO_PUBLIC_APP_VARIANTenv variable - Verify both variants install side-by-side on a physical device or simulator
Out of scope: Staging / QA environment variants, EAS Submit configuration, CI pipeline changes.
Dependencies: Expo SDK 53+; EAS Build account.
Acceptance criteria:
- Two separate app icons appear on the home screen with distinct names and icons
- Each variant resolves to the correct API base URL (dev vs prod)
- Running
eas build --profile developmentandeas build --profile productionproduce different bundle identifiers
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Configure Expo app variants so dev and production builds can be installed side by side on the same device.
Goal: Use Expo's app variants pattern (https://expo.dev/blog/app-variants-side-by-side) to allow simultaneous installation of development and production builds.
Files to create or modify:
app.config.js— convert fromapp.jsonto dynamic config, readprocess.env.EXPO_PUBLIC_APP_VARIANTeas.json— addenvblock to each build profile settingEXPO_PUBLIC_APP_VARIANTassets/icon-dev.png— duplicate of the app icon with a visual DEV badge overlayconstants/config.ts— exportAPP_VARIANTandAPI_BASE_URLderived from the env variable
Step-by-step implementation:
- Rename
app.jsontoapp.config.jsand export a function:export default ({ config }) => ({ ...config, ... }). - At the top, read:
const variant = process.env.EXPO_PUBLIC_APP_VARIANT ?? 'production';. - Return variant-specific values:
name:variant === 'development' ? 'MyApp (Dev)' : 'MyApp'ios.bundleIdentifier:variant === 'development' ? 'com.myapp.dev' : 'com.myapp'android.package: same patternicon:variant === 'development' ? './assets/icon-dev.png' : './assets/icon.png'
- In
eas.json, underbuild.development.envsetEXPO_PUBLIC_APP_VARIANT=development; underbuild.production.envsetEXPO_PUBLIC_APP_VARIANT=production. - In
constants/config.ts, exportAPI_BASE_URL = variant === 'development' ? 'https://api.dev.myapp.com' : 'https://api.myapp.com'. - Build both:
eas build --profile development --platform iosandeas build --profile production --platform ios. - Install both on the same simulator and verify two distinct icons appear.
Acceptance criteria checklist:
- Two apps install without overwriting each other on the same device
- Dev app shows a visual indicator (different icon or "(Dev)" name suffix)
-
Constants.expoConfig.ios.bundleIdentifierreturns different values per build - API base URL resolves to the correct endpoint at runtime in each variant
🟧 Chunk 2 — Implement Continuous Delivery with EAS Workflows and Expo Updates
Goal: Eliminate manual release steps by automating native builds and OTA updates so every merged PR can ship to users without human intervention — the same pipeline Posh used to go from weekly manual releases to continuous delivery.
Scope:
- Install and configure
expo-updateswith channel-based routing - Write an EAS Workflow YAML triggered on push to
main - Add a fingerprint check step: only trigger a full native build when native code changes; otherwise publish an OTA update
- Configure Slack or email notifications on build failure
Out of scope: App Store submission automation, rollback mechanisms, A/B testing OTA channels.
Dependencies: EAS Build account; expo-updates installed; GitHub (or equivalent CI) connected to EAS.
Acceptance criteria:
- Merging a JS-only change to
mainpublishes an OTA update without triggering a native build - Merging a native-layer change (e.g. new package with native code) triggers a full EAS Build automatically
- A stakeholder can confirm the update is live on their device within 10 minutes of the merge
Estimated effort: M
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Automate the release pipeline with EAS Workflows and Expo Updates for continuous delivery (inspired by https://expo.dev/blog/posh-manual-weekly-releases-to-continuous-delivery-with-expo).
Goal: Configure a CI/CD pipeline where JS-only changes ship as instant OTA updates and native changes trigger full EAS Builds — zero manual steps post-merge.
Files to create or modify:
.eas/workflows/deploy.yml— new EAS Workflow definitioneas.json— ensurechannelis configured per build profileapp.config.js— ensureexpo.updates.urlis set correctly
Step-by-step implementation:
- Install expo-updates:
npx expo install expo-updates. - Run
eas update:configureto generate channel configuration. - In
eas.json, set"channel": "production"underbuild.production. - Create
.eas/workflows/deploy.yml:
on:
push:
branches: [main]
jobs:
deploy:
steps:
- uses: fingerprint
- if: fingerprint.changed
run: eas build --profile production --non-interactive
- if: "!fingerprint.changed"
run: eas update --branch production --message "OTA ${{ github.sha }}"
- In the EAS dashboard under Notifications, configure a Slack webhook for build failures.
- Test: merge a one-line JS change → confirm OTA publishes. Merge a new native dependency → confirm full build triggers.
Acceptance criteria checklist:
- OTA update is live within 10 min of a JS-only merge to
main - Fingerprint change triggers a full EAS Build automatically
- Build failure sends a Slack / email notification without any manual check
- No developer action required post-merge for either path
🟧 Chunk 3 — Implement Deferred Deep Linking with Expo Router
Goal: Ensure users who tap a deep link before installing the app are routed to the correct in-app screen immediately after install completes — reducing drop-off on acquisition campaigns and share flows.
Scope:
- Capture the initial URL on first launch using
expo-linking'sgetInitialURL() - Persist the pending URL in
AsyncStoragewhen no matching screen is rendered yet - After authentication or onboarding completes, consume the pending URL and navigate to the target route
- Clear the pending URL from storage after a single use
- Write a unit test for the store → navigate → clear lifecycle
Out of scope: Branch.io / AppsFlyer / Firebase Dynamic Links integration, App Clips, Smart App Banners.
Dependencies: Expo Router v4+; expo-linking; @react-native-async-storage/async-storage.
Acceptance criteria:
- Tapping a deep link on a device without the app installed stores the URL on first launch
- After install and onboarding, the user lands on the correct screen automatically
- The deferred URL is cleared from storage after navigation (no infinite redirect loop)
- A unit test verifies the store → navigate → clear flow independently of the UI
Estimated effort: M
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Deferred deep linking with Expo Router (https://expo.dev/blog/deferred-deep-linking-the-right-way).
Goal: Route users to the correct screen after install when they tapped a deep link before the app was installed.
Files to create or modify:
hooks/useDeferredLink.ts— new hook: captures initial URL → stores in AsyncStorage → navigates post-authapp/_layout.tsx— calluseDeferredLinkafter auth state resolves__tests__/useDeferredLink.test.ts— unit tests for store / navigate / clear cycle
Step-by-step implementation:
npx expo install expo-linking @react-native-async-storage/async-storage- Create
hooks/useDeferredLink.ts:
import * as Linking from 'expo-linking';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useRouter } from 'expo-router';
const KEY = 'pendingDeepLink';
export function useDeferredLink(isAuthenticated: boolean) {
const router = useRouter();
useEffect(() => {
Linking.getInitialURL().then(url => {
if (url) AsyncStorage.setItem(KEY, url);
});
}, []);
useEffect(() => {
if (!isAuthenticated) return;
AsyncStorage.getItem(KEY).then(url => {
if (!url) return;
AsyncStorage.removeItem(KEY);
const { path } = Linking.parse(url);
if (path) router.replace(`/${path}`);
});
}, [isAuthenticated]);
}
- In
app/_layout.tsx, calluseDeferredLink(isAuthenticated)after the auth check resolves. - Write tests mocking
Linking.getInitialURLreturning a URL, verifyingAsyncStorage.setItemis called, then simulatingisAuthenticated = trueand verifyingrouter.replaceis called and the key is removed. - Test manually: paste a deep link into Safari on iOS Simulator before launching the app, launch the app, complete onboarding, and confirm you land on the correct screen.
Acceptance criteria checklist:
- Deep link URL is persisted across fresh install
- User lands on the correct screen after completing onboarding/auth
- Pending URL is removed from AsyncStorage after navigation
- Unit tests pass for store, navigate, and clear scenarios
🟧 Chunk 4 — Set Up EAS Observe Before General Availability (August 20)
Goal: Enable EAS Observe on your production channel now — before its August 20 GA date — to start capturing real-world crash signals, session data, and performance regressions from production users.
Scope:
- Enable EAS Observe in the Expo dashboard for the production channel
- Configure at least one alert rule (JS crash rate threshold)
- Trigger a test event to confirm data flows into the Observe dashboard
- Verify a non-technical stakeholder can read session traces without engineering support
Out of scope: Custom dashboards, third-party monitoring integrations (Sentry, Datadog), non-production channel configuration.
Dependencies: EAS account with active production builds; Expo SDK 57 recommended; expo-updates configured.
Acceptance criteria:
- EAS Observe dashboard shows live session data after a production build is run
- At least one alert rule is active and fires on a test crash event
- A stakeholder can navigate to the dashboard and read a session trace independently
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Enable EAS Observe for production monitoring before its August 20, 2026 GA date (https://expo.dev/changelog/eas-observe-moves-to-general-availability-on-august-20).
Goal: Start capturing production crash and performance data in EAS Observe to catch regressions before users report them.
Files to create or modify:
eas.json— confirm"channel": "production"is set in the production build profileapp.config.js— ensureexpo.updates.urlis configured (required for Observe)
Step-by-step implementation:
- Open the Expo dashboard → your project → Observe tab.
- Click Enable on the production channel.
- In
eas.json, confirm your production profile has"channel": "production"underupdates. - Create an alert rule: Alerts → New Rule → JS Crash Rate > 1% → Notify via email/Slack.
- In a dev build, add a temporary
throw new Error('test-observe-crash')behind a hidden gesture (e.g. triple-tap), trigger it, and verify the event appears in the Observe timeline within 60 seconds. - Remove the test crash.
- Share the dashboard link with a non-technical stakeholder and confirm they can read the session data.
Acceptance criteria checklist:
- EAS Observe is enabled on the production channel
- Live session data appears in the dashboard within 60 s of app launch
- Test crash event is visible in the Observe timeline
- Alert rule is active and confirmed to notify on threshold breach
- Non-engineer stakeholder can read session traces without assistance
⚛️ Chunk 5 — Upgrade to React 19.2.8 and Audit Server Action Security
Goal: Apply the React 19.2.8 security patch (fixes a DoS vulnerability on server function endpoints) and audit any exposed server actions in the project to prevent maliciously crafted requests from crashing the server.
Scope:
- Bump
react,react-dom, and@types/reactto 19.2.8 inpackage.json - Run the test suite to confirm no regressions
- Audit all server actions / API route handlers for missing input validation
- Add
zodschema validation to at least one unvalidated server action as a reference implementation
Out of scope: Migrating from React 18 to 19, refactoring existing state management, Next.js or Remix-specific changes beyond the patch.
Dependencies: React 19.x already in use; existing test suite; zod (or equivalent validation library).
Acceptance criteria:
react,react-dom, and@types/reactare all at version 19.2.8 (or ≥ 19.1.9 / ≥ 19.0.8 for older lines)- All existing tests pass after the upgrade
- At least one server action validates its input with a schema before processing
- A stakeholder can confirm no new crashes appear in monitoring within 24 hours of deploy
Estimated effort: S
**Copy/paste this prompt:**
Implement the following React Native chunk for your mobile app: Upgrade to React 19.2.8 and add server action input validation to patch the DoS vulnerability (https://react.statuscode.com/issues/484).
Goal: Apply the security patch for the DoS vulnerability in React 19 server function endpoints and harden server actions against maliciously crafted requests.
Files to create or modify:
package.json— bumpreact,react-dom,@types/reactto 19.2.8app/actions/exampleAction.ts— addzodschema validation as a reference implementation
Step-by-step implementation:
- Update dependencies:
npm install react@19.2.8 react-dom@19.2.8 @types/react@19.2.8
- Run
npm testand fix any breaking changes (typically none for a patch release). - Install
zodif not present:npm install zod. - In each server action file, add input validation:
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
message: z.string().max(1000),
});
export async function submitContactForm(input: unknown) {
const data = schema.parse(input); // throws ZodError on invalid input
// ... rest of the action
}
- Wrap the
schema.parsecall in a try/catch and return a structured error response instead of letting it propagate. - Deploy and monitor error rates for 24 hours.
Acceptance criteria checklist:
-
reactandreact-domare at 19.2.8 inpackage-lock.json - All existing tests pass after the upgrade
- At least one server action validates input with a zod schema
- Invalid input returns a structured error, not a 500 crash
- No new errors appear in monitoring within 24 h of deploy