Skip to content

Expo on iPhone Duo: EAS Build, app.json and native tabs

Ingenious Techlab TeamUpdated 2026-09-196 min read

Contents · 6 sections
  1. Expo iPhone Duo checklist
  2. Your build image decides what iPhone Duo shows
  3. The portrait lock in app.json
  4. Native tabs get the system’s side column
  5. The React Native parts
  6. Tooling on Xcode 27

An Expo app is a React Native app, so everything in our React Native guide applies. But three Expo-specific choices decide what iPhone Duo actually shows: the image EAS builds your app on, what app.json asks for, and which tab bar Expo Router draws. This checklist covers all three, and each item links to the detail.

Expo iPhone Duo checklist

  1. Check which Xcode builds your app. EAS’s newest iOS image uses Xcode 26.6, so cloud builds today do not include the iOS 27 SDK.
  2. Do the layout work before the rebuild. The build that moves you to the new SDK is what exposes layout bugs, not the device.
  3. Change "orientation": "portrait" to "default". Expo’s default template sets the lock, and the inner display ignores it.
  4. Leave ios.requireFullScreen off. iPhone Duo honours the key but scales your app instead of exempting it.
  5. Switch to NativeTabs so iOS can move your tab bar into the side column.
  6. Read size with useWindowDimensions() instead of a module-scope Dimensions.get('window').
  7. Pad left and right separately with react-native-safe-area-context; React Native’s own SafeAreaView is deprecated.
  8. Stop choosing layouts with Device.deviceType. iPhone Duo is a phone with a regular-width display.
  9. Keep media playing in Split View by pausing on background, not inactive.
  10. Update eas-cli to 24.4.2 or later before building on Xcode 27.
  11. Test every pose in Device Hub with Xcode 27.1 beta, released 18 September.
  12. Treat App Store screenshots as optional for now. Apple lists iPhone Duo sizes, but uploads open later this year.

Expo has published no iPhone Duo guidance, so the Expo side of this is our analysis. Every Expo fact below links to Expo’s own documentation or code, checked on 15 September 2026.

Your build image decides what iPhone Duo shows

Apple defined three tiers of iPhone Duo behaviour, and which one your app gets depends only on the SDK it was built against:

Built against What your app gets on the inner display
Not the iOS 27 SDK Runs at a familiar size and aspect ratio
iOS 27 SDK Extends left of the status bar area
iOS 27.1 SDK Reaches the screen edge; standard bar buttons move to the side

For most Expo teams the SDK is not a choice made in Xcode. It comes from the EAS Build image. As of 15 September, Expo’s build infrastructure page lists no iOS image with Xcode 27. The latest and sdk-57 aliases point to macos-tahoe-26.5-xcode-26.6.

So an Expo app built on EAS today reaches iPhone Duo in the first tier. It runs and nothing crashes, but it does not use the display.

EAS image with Xcode 26: familiar size versus Built with the iOS 27.1 SDK: full screenTwo iPhone Duo inner displays, 626 by 890 points. Left: an app built without the iOS 27 SDK runs in a 402-point-wide phone-shaped window with black bars either side. Right: the same app built with the iOS 27.1 SDK fills the display edge to edge with a two-column layout.402 pt626 pt

Left: EAS image with Xcode 26: familiar size

// eas.json: "latest" is Xcode 26.6
{
  "build": {
    "production": {
      "ios": { "image": "latest" }
    }
  }
}

Right: Built with the iOS 27.1 SDK: full screen

# Uses the Xcode selected on your Mac
xcrun --sdk iphoneos --show-sdk-version
# 27.1 → build on this machine
eas build --platform ios --local
EAS images as of 15 September 2026, when Expo’s newest iOS image used Xcode 26.6. The narrower window on the left is illustrative.How to fix it — EAS image with Xcode 26: familiar size

To see the full-screen result now, build on a Mac with Xcode 27.1 beta selected, using eas build --platform ios --local. Test with it, but do not submit from it: App Store builds need the release version of Xcode.

The break arrives with a rebuild

The first tier is safe. It is also temporary. Apple has announced that from April 2027, apps uploaded to App Store Connect must be built with the iOS 27 SDK or later. Expo aims to support stable Xcode releases on EAS, so newer images will follow.

The risky moment is the day your build moves to a newer image. The app claims more of the screen, and every assumption in the layout becomes visible at once, even though nobody changed a line of code. Do the layout work in this checklist first, so the rebuild is a non-event.

The portrait lock in app.json

Expo’s default project template sets "orientation": "portrait", so a new Expo app starts life with a portrait lock that nobody decided on. Apple’s Tech Talk is explicit that the inner display does not honour supported interface orientations. The lock is ignored there, and the app is laid out sideways when the device is held that way.

Portrait lock from the template versus No lock; layout chosen by widthTwo iPhone Duo inner displays held landscape, 890 by 626 points. Left: a portrait-locked layout is shown anyway, and its full-width hero image runs off the bottom of the screen. Right: a layout chosen by width shows a sidebar beside the detail view.890 × 626 pt890 × 626 pt

Left: Portrait lock from the template

// app.json (default template)
{
  "expo": {
    "orientation": "portrait"
  }
}

Right: No lock; layout chosen by width

// app.json
{
  "expo": {
    "orientation": "default"
  }
}
Drawn to iPhone Duo’s point dimensions.How to fix it — Portrait lock from the template

In Expo’s app config, orientation accepts default, portrait or landscape, and default means no lock. Pair it with a layout chosen by width, such as a two-column view at 600 points or wider.

requireFullScreen and orientation locks

ios.requireFullScreen maps to UIRequiresFullScreen, the key that opts an iPad app out of resizing. It is worth being precise about what it does here, because the answer is not the one most people expect.

Apple’s Tech Talk says iPhone Duo continues to honour the key — and then removes everything you would have set it for. Your app still resizes when someone opens or closes the device. Your supported orientations are respected, but the app scales on the inner display, including in Split View multitasking. Meanwhile the companion Tech Talk on multiple displays states plainly that all apps take part in multitasking on iPhone Duo.

So the flag does not buy an exemption; it buys a scaled presentation of an app that is still being resized. It sometimes gets turned on for an unrelated reason: the expo-screen-orientation docs note that locking orientation on iPad requires Requires Full Screen. Leave it off on iPhone Duo and build a layout that works at any width.

Native tabs get the system’s side column

On iPhone Duo, Apple’s guidelines move standard tab bars and toolbars into a column at the side on the closed outer display and on the inner display in landscape. That only happens to bars the system draws.

Expo Router’s Tabs wraps React Navigation’s JavaScript tab bar, so it stays at the bottom. NativeTabs is backed by UITabBarController on iOS. Import it from expo-router/unstable-native-tabs in SDK 54 to 57, and from expo-router/native-tabs from SDK 58. Expo’s default template on its main branch already uses it.

JS tab bar: stays at the bottom versus Native tabs: expected at the sideTwo closed iPhone Duo outer displays, 466 by 678 points. Left: a tab bar drawn by the app stays across the bottom, taking height from content on a short, wide screen. Right: a system tab bar in a column down the right side, bottom-aligned below the Dynamic Island, leaving the full height for content.466 × 678 pt466 × 678 pt

Left: JS tab bar: stays at the bottom

import { Tabs } from 'expo-router';

// Drawn by React Navigation in JS
export default function Layout() {
  return <Tabs />;
}

Right: Native tabs: expected at the side

import { NativeTabs } from
  'expo-router/unstable-native-tabs';

// UITabBarController on iOS
export default function Layout() {
  return (
    <NativeTabs>
      <NativeTabs.Trigger name="home" />
    </NativeTabs>
  );
}
Import path for Expo SDK 54–57; from SDK 58 it is expo-router/native-tabs. Side placement for native tabs follows from Apple’s guidance and is not yet verified on the device.How to fix it — JS tab bar: stays at the bottom

We expect a UITabBarController-backed bar to get the same side placement as any native app built with the iOS 27.1 SDK. That is not yet verified on the device, so check it in Device Hub before you ship.

The React Native parts

Under Expo, the layout rules are React Native’s. Here is where common patterns in Expo projects stand:

Expo on iPhone Duo: what works, what breaks

  • Looks datedEAS Build latest image (Xcode 26.6)No iOS 27 SDK: runs at a familiar size, not full screen.
  • WorksA build with Xcode 27.1Reaches the screen edge — do the layout work first.
  • Breaks"orientation": "portrait" in app.jsonThe inner display ignores it. The default template sets it.
  • Breaksios.requireFullScreen: trueHonoured, but the app scales instead of being exempt.
  • Looks datedTabs from expo-routerReact Navigation’s JavaScript tab bar stays at the bottom.
  • UnverifiedNativeTabs from expo-routerUITabBarController on iOS; expected to move to the side column.
  • WorksuseWindowDimensions()Re-renders on fold, unfold and Split View.
  • BreaksModule-scope Dimensions.get('window')Captured once at launch.
  • WorksSafeAreaView from react-native-safe-area-contextHandles each edge separately.
  • Looks datedSafeAreaView from react-nativeDeprecated since React Native 0.81.
  • BreaksLayouts chosen by Device.deviceTypeiPhone Duo is a phone with a regular-width display.
  • Breakseas-cli before 24.4.2 with Xcode 27`eas build:dev` cannot find Device Hub and fails.

The React Native blockers are drawn in full, with before-and-after code, on the React Native iPhone Duo page. Two are worth singling out for Expo projects:

  • Safe areas. React Native 0.81 deprecated its built-in SafeAreaView in favour of react-native-safe-area-context. Use that library, and apply insets.left and insets.right on their own, never one value for both.
  • Split View. Code that pauses video or animation when AppState leaves active will freeze content that is still on screen.

expo-device and iPhone Duo

Device.deviceType reports a phone or a tablet, and iPhone Duo is a phone. A layout that serves its phone design for PHONE will stretch a single column across a 626-point, regular-width display. Branch on the window’s width instead.

Recognising the model by name is still in progress: an open pull request adds iPhone19,4 as “iPhone Duo” to expo-device’s model list.

Tooling on Xcode 27

Xcode 27 replaced the Simulator app with Device Hub. That broke eas build:dev, which looked for the old app by name. The issue was fixed in eas-cli 24.4.2, so update before you build locally on Xcode 27.

Xcode 27.1 beta, released on 18 September, adds the iPhone Duo simulator to Device Hub, and Apple’s Tech Talks describe controls to open, close, rotate and fold it. The simulator page covers its requirements and known issues.

Built your Expo app with an AI tool? The same checklist applies, with a few extra patterns covered in why vibe-coded apps break on iPhone Duo.

React Native on iPhone Duo

No first-party support. Flexbox layout adapts, but cached dimensions, orientation locking and safe-area assumptions all need attention.

Read the React Native guide

Related

Free evaluation of your app

Run the checklist — the blockers are enough — send it to us, and we will reply with your outstanding items prioritised and a realistic effort estimate. No call, no obligation.