{"id":"expo","kind":"sdk","name":"Expo","slug":"expo","description":"Official toolchain for React Native apps: Expo Router, EAS Build, and native modules.","vendor":"Expo","languages":["typescript","javascript","swift","kotlin"],"categories":["devtools"],"homepage":"https://expo.dev","docsUrl":"https://docs.expo.dev","githubUrl":"https://github.com/expo/skills","packages":[{"registry":"npm","name":"expo","url":"https://www.npmjs.com/package/expo"}],"tags":["react-native","mobile","eas"],"skills":[{"name":"expo-dev-client","url":"https://github.com/expo/skills/tree/main/plugins/expo/skills/expo-dev-client","install":"npx skills add expo/skills --skill expo-dev-client","sdk":"expo","key":"expo/expo-dev-client","description":"Framework (OSS). Build and distribute Expo development clients locally or via TestFlight for internal testing. For production TestFlight releases and store submission, use the eas-app-stores skill.","hasContent":true,"content":"---\nname: expo-dev-client\ndescription: Framework (OSS). Build and distribute Expo development clients locally or via TestFlight for internal testing. For production TestFlight releases and store submission, use the eas-app-stores skill.\nversion: 1.1.0\nlicense: MIT\n---\n\nUse EAS Build to create development clients for testing native code changes on physical devices. Use this for creating custom Expo Go clients for testing branches of your app.\n\n> **Free locally; cloud builds are paid.** `expo-dev-client` itself is open source and building locally is free. Building or distributing via EAS Build/TestFlight uses your EAS plan's build minutes and needs a paid Apple Developer account for device/TestFlight distribution. See https://expo.dev/pricing.\n\n## Important: When Development Clients Are Needed\n\n**Development clients are the recommended setup for any real or production app.** Expo Go is a playground for learning and quick experiments with the native libraries it bundles; most apps outgrow it and move to a development client. See [Expo Go vs. development builds](https://docs.expo.dev/develop/development-builds/introduction/) for the full reasoning.\n\nYou need a dev client ONLY when using:\n\n- Local Expo modules (custom native code)\n- Apple targets (widgets, app clips, extensions)\n- Third-party native modules not in Expo Go\n- Config plugins, or testing remote push notifications and App/Universal Links\n\n## EAS Configuration\n\nEnsure `eas.json` has a development profile:\n\n```json\n{\n  \"cli\": {\n    \"version\": \">= 16.0.1\",\n    \"appVersionSource\": \"remote\"\n  },\n  \"build\": {\n    \"production\": {\n      \"autoIncrement\": true\n    },\n    \"development\": {\n      \"autoIncrement\": true,\n      \"developmentClient\": true\n    }\n  },\n  \"submit\": {\n    \"production\": {},\n    \"development\": {}\n  }\n}\n```\n\nKey settings:\n\n- `developmentClient: true` - Bundles expo-dev-client for development builds\n- `autoIncrement: true` - Automatically increments build numbers\n- `appVersionSource: \"remote\"` - Uses EAS as the source of truth for version numbers\n\n## Building for TestFlight\n\nBuild iOS dev client and submit to TestFlight in one command:\n\n```bash\neas build -p ios --profile development --submit\n```\n\nThis will:\n\n1. Build the development client in the cloud\n2. Automatically submit to App Store Connect\n3. Send you an email when the build is ready in TestFlight\n\nAfter receiving the TestFlight email:\n\n1. Download the build from TestFlight on your device\n2. Launch the app to see the expo-dev-client UI\n3. Connect to your local Metro bundler or scan a QR code\n\n## Building Locally\n\nBuild a development client on your machine:\n\n```bash\n# iOS (requires Xcode)\neas build -p ios --profile development --local\n\n# Android\neas build -p android --profile development --local\n```\n\nLocal builds output:\n\n- iOS: `.ipa` file\n- Android: `.apk` or `.aab` file\n\n## Installing Local Builds\n\nInstall iOS build on simulator:\n\n```bash\n# Find the .app in the .tar.gz output\ntar -xzf build-*.tar.gz\nxcrun simctl install booted ./path/to/App.app\n```\n\nInstall iOS build on device (requires signing):\n\n```bash\n# Use Xcode Devices window or ideviceinstaller\nideviceinstaller -i build.ipa\n```\n\nInstall Android build:\n\n```bash\nadb install build.apk\n```\n\n## Building for Specific Platform\n\n```bash\n# iOS only\neas build -p ios --profile development\n\n# Android only\neas build -p android --profile development\n\n# Both platforms\neas build --profile development\n```\n\n## Checking Build Status\n\n```bash\n# List recent builds\neas build:list\n\n# View build details\neas build:view\n```\n\n## Using the Dev Client\n\nOnce installed, the dev client provides:\n\n- **Development server connection** - Enter your Metro bundler URL or scan QR\n- **Build information** - View native build details\n- **Launcher UI** - Switch between development servers\n\nConnect to local development:\n\n```bash\n# Start Metro bundler\nnpx expo start --dev-client\n\n# Scan QR code with dev client or enter URL manually\n```\n\n## Troubleshooting\n\n**Build fails with signing errors:**\n\n```bash\neas credentials\n```\n\n**Clear build cache:**\n\n```bash\neas build -p ios --profile development --clear-cache\n```\n\n**Check EAS CLI version:**\n\n```bash\neas --version\neas update\n```\n\n## Submitting Feedback\nIf you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:\n```bash\nnpx --yes submit-expo-feedback@latest --category skills --subject \"expo-dev-client\" \"<actionable feedback>\"\n```\nOnly submit when you have something specific and actionable to report. Include as much relevant context as possible.\n","contentSource":"https://raw.githubusercontent.com/expo/skills/main/plugins/expo/skills/expo-dev-client/SKILL.md","contentFetchedAt":"2026-07-28T23:15:38.795Z"},{"name":"expo-native-ui","url":"https://github.com/expo/skills/tree/main/plugins/expo/skills/expo-native-ui","install":"npx skills add expo/skills --skill expo-native-ui","sdk":"expo","key":"expo/expo-native-ui","description":"Framework (OSS). Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill.","hasContent":true,"content":"---\nname: expo-native-ui\ndescription: Framework (OSS). Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill.\nversion: 1.1.1\nlicense: MIT\n---\n\n# Expo Native UI Guidelines\n\nFor routes, links, stacks, tabs, modals, sheets, and headers, use the `expo-router` skill.\n\n## References\n\nConsult these resources as needed:\n\n```\nreferences/\n  animations.md          Reanimated: entering, exiting, layout, scroll-driven, gestures\n  controls.md            Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker\n  gradients.md           CSS gradients via experimental_backgroundImage (New Arch only)\n  icons.md               SF Symbols via expo-image (sf: source), names, animations, weights\n  media.md               Camera, audio, video, and file saving\n  storage.md             SQLite, AsyncStorage, SecureStore\n  visual-effects.md      Blur (expo-blur) and liquid glass (expo-glass-effect)\n  webgpu-three.md        3D graphics, games, GPU visualizations with WebGPU and Three.js\n```\n\n## Running the App\n\n**CRITICAL: Always try Expo Go first before creating custom builds.**\n\nMost Expo apps work in Expo Go without any custom native code. Before running `npx expo run:ios` or `npx expo run:android`:\n\n1. **Start with Expo Go**: Run `npx expo start` and scan the QR code with Expo Go\n2. **Check if features work**: Test your app thoroughly in Expo Go\n3. **Only create custom builds when required** - see below\n\n### When Custom Builds Are Required\n\nYou need `npx expo run:ios/android` or `eas build` ONLY when using:\n\n- **Local Expo modules** (custom native code in `modules/`)\n- **Apple targets** (widgets, app clips, extensions via `@bacons/apple-targets`)\n- **Third-party native modules** not included in Expo Go\n- **Custom native configuration** that can't be expressed in `app.json`\n\n### When Expo Go Works\n\nExpo Go supports a huge range of features out of the box:\n\n- All `expo-*` packages (camera, location, notifications, etc.)\n- Expo Router navigation\n- Most UI libraries (reanimated, gesture handler, etc.)\n- Push notifications, deep links, and more\n\n**If you're unsure, try Expo Go first.** Creating custom builds adds complexity, slower iteration, and requires Xcode/Android Studio setup.\n\n## Code Style\n\n- Be cautious of unterminated strings. Ensure nested backticks are escaped; never forget to escape quotes correctly.\n- Always use import statements at the top of the file.\n- Always use kebab-case for file names, e.g. `comment-card.tsx`\n- Never use special characters in file names\n- Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.\n\n## Library Preferences\n\n- Never use modules removed from React Native such as Picker, WebView, SafeAreaView, or AsyncStorage\n- Never use legacy expo-permissions\n- `expo-audio` not `expo-av`\n- `expo-video` not `expo-av`\n- `expo-image` with `source=\"sf:name\"` for SF Symbols, not `expo-symbols` or `@expo/vector-icons`\n- `react-native-safe-area-context` not react-native SafeAreaView\n- `process.env.EXPO_OS` not `Platform.OS`\n- `React.use` not `React.useContext`\n- `expo-image` Image component instead of intrinsic element `img`\n- `expo-glass-effect` for liquid glass backdrops\n- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark)\n- In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`)\n\n## Responsiveness\n\n- Always wrap root component in a scroll view for responsiveness\n- Use `<ScrollView contentInsetAdjustmentBehavior=\"automatic\" />` instead of `<SafeAreaView>` for smarter safe area insets\n- `contentInsetAdjustmentBehavior=\"automatic\"` should be applied to FlatList and SectionList as well\n- Use flexbox instead of Dimensions API\n- ALWAYS prefer `useWindowDimensions` over `Dimensions.get()` to measure screen size\n\n## Behavior\n\n- Use expo-haptics conditionally on iOS to make more delightful experiences\n- Use views with built-in haptics like `<Switch />` from React Native and `@react-native-community/datetimepicker`\n- When a route belongs to a Stack, its first child should almost always be a ScrollView with `contentInsetAdjustmentBehavior=\"automatic\"` set\n- When adding a `ScrollView` to the page it should almost always be the first component inside the route component\n- Use the `<Text selectable />` prop on text containing data that could be copied\n- Consider formatting large numbers like 1.4M or 38k\n- Never use intrinsic elements like 'img' or 'div' unless in a webview or Expo DOM component\n\n# Styling\n\nFollow Apple Human Interface Guidelines.\n\n## General Styling Rules\n\n- Prefer flex gap over margin and padding styles\n- Prefer padding over margin where possible\n- Always account for safe area, either with stack headers, tabs, or ScrollView/FlatList `contentInsetAdjustmentBehavior=\"automatic\"`\n- Ensure both top and bottom safe area insets are accounted for\n- Inline styles not StyleSheet.create unless reusing styles is faster\n- Add entering and exiting animations for state changes\n- Use `{ borderCurve: 'continuous' }` for rounded corners unless creating a capsule shape\n- ALWAYS use a navigation stack title instead of a custom text element on the page\n- When padding a ScrollView, use `contentContainerStyle` padding and gap instead of padding on the ScrollView itself (reduces clipping)\n- CSS and Tailwind are not supported - use inline styles\n\n## Colors\n\nUse the `Color` API from `expo-router` for native semantic colors. It is a type-safe wrapper over `PlatformColor` that exposes iOS UIKit colors through `Color.ios.*` and Android Material 3 colors through `Color.android.material.*` (static) or `Color.android.dynamic.*` (adapts to the user's wallpaper on Android 12+). These resolve on-device and automatically adapt to light/dark mode and accessibility settings, so you no longer maintain separate light/dark hex tables or a `colors.web.ts` file.\n\n`Color` is platform-specific, so wrap each value in `Platform.select` with a `default` hex fallback for web. Centralize the palette in `theme/colors.ts` and import `colors` everywhere:\n\n```tsx\n// theme/colors.ts\nimport { Platform } from \"react-native\";\nimport { Color } from \"expo-router\";\n\nexport const colors = {\n  label: Platform.select({\n    ios: Color.ios.label,\n    android: Color.android.dynamic.onSurface,\n    default: \"#000000\",\n  })!,\n  secondaryLabel: Platform.select({\n    ios: Color.ios.secondaryLabel,\n    android: Color.android.dynamic.onSurfaceVariant,\n    default: \"#3c3c43\",\n  })!,\n  separator: Platform.select({\n    ios: Color.ios.separator,\n    android: Color.android.dynamic.outlineVariant,\n    default: \"#c6c6c8\",\n  })!,\n  systemBackground: Platform.select({\n    ios: Color.ios.systemBackground,\n    android: Color.android.dynamic.surface,\n    default: \"#ffffff\",\n  })!,\n  systemBlue: Platform.select({\n    ios: Color.ios.systemBlue,\n    android: Color.android.dynamic.primary,\n    default: \"#007aff\",\n  })!,\n};\n```\n\n```tsx\nimport { colors } from \"@/theme/colors\";\n\n<View style={{ backgroundColor: colors.systemBackground }}>\n  <Text style={{ color: colors.label }}>Title</Text>\n</View>;\n```\n\n- iOS re-resolves these colors automatically when the system theme changes. On Android, call `useColorScheme()` inside any component that renders them so it re-renders when the theme flips (required when React Compiler memoizes the component).\n- Don't pass `Color` / `PlatformColor` values into Reanimated styles — use static colors there (see `references/animations.md`).\n- `Platform.select({...})!` returns `string | OpaqueColorValue`. Most React Native style props accept `ColorValue` (`string | OpaqueColorValue`) so this works fine. But some third-party props only accept `string` (e.g. `tintColor` on `expo-image`). Cast when needed: `colors.label as string`.\n\n## Text Styling\n\n- Add the `selectable` prop to every `<Text/>` element displaying important data or error messages\n- Counters should use `{ fontVariant: 'tabular-nums' }` for alignment\n\n## Shadows\n\nUse CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevation styles.\n\n```tsx\n<View style={{ boxShadow: \"0 1px 2px rgba(0, 0, 0, 0.05)\" }} />\n```\n\n'inset' shadows are supported.\n\n## Submitting Feedback\nIf you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:\n```bash\nnpx --yes submit-expo-feedback@latest --category skills --subject \"expo-native-ui\" \"<actionable feedback>\"\n```\nOnly submit when you have something specific and actionable to report. Include as much relevant context as possible.\n","contentSource":"https://raw.githubusercontent.com/expo/skills/main/plugins/expo/skills/expo-native-ui/SKILL.md","contentFetchedAt":"2026-07-28T23:15:38.856Z"},{"name":"expo-router","url":"https://github.com/expo/skills/tree/main/plugins/expo/skills/expo-router","install":"npx skills add expo/skills --skill expo-router","sdk":"expo","key":"expo/expo-router","description":"Framework (OSS). Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars.","hasContent":true,"content":"---\nname: expo-router\ndescription: Framework (OSS). Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars.\nversion: 1.0.1\nlicense: MIT\n---\n\n# Expo Router Navigation\n\nNavigation and routing for Expo Router apps. For screen styling, colors, controls, animations, media, and visual effects, use the `expo-native-ui` skill.\n\n## References\n\nConsult these resources as needed:\n\n```\nreferences/\n  route-structure.md     Route conventions, dynamic routes, groups, folder organization\n  tabs.md                NativeTabs, migration from JS tabs, iOS 26 features\n  toolbar-and-headers.md Stack headers and toolbar buttons, menus, search (iOS only)\n  form-sheet.md          Form sheets in expo-router: configuration, footers and background interaction.\n  search.md              Search bar with headers, useSearch hook, filtering patterns\n  zoom-transitions.md    Apple Zoom: fluid zoom transitions with Link.AppleZoom (iOS 18+)\n```\n\n## Code Style\n\n- Always use kebab-case for file names, e.g. `comment-card.tsx`\n- Always remove old route files when moving or restructuring navigation\n- Never use special characters in file names\n- Configure tsconfig.json with path aliases, and prefer aliases over relative imports for refactors.\n\n## Routes\n\nSee `./references/route-structure.md` for detailed route conventions.\n\n- Routes belong in the `app` directory.\n- Never co-locate components, types, or utilities in the app directory. This is an anti-pattern.\n- Ensure the app always has a route that matches \"/\", it may be inside a group route.\n\n## Library Preferences\n\n- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark). See `expo-native-ui` for the full color palette pattern.\n- In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`)\n\n## Behavior\n\n- Prefer `Stack.SearchBar` to add a search bar to a screen\n\n# Navigation\n\n## Link\n\nUse `<Link href=\"/path\" />` from 'expo-router' for navigation between routes.\n\n```tsx\nimport { Link } from 'expo-router';\n\n// Basic link\n<Link href=\"/path\" />\n\n// Wrapping custom components\n<Link href=\"/path\" asChild>\n  <Pressable>...</Pressable>\n</Link>\n```\n\nWhenever possible, include a `<Link.Preview>` to follow iOS conventions. Add context menus and previews frequently to enhance navigation.\n\n## Stack\n\n- ALWAYS use `_layout.tsx` files to define stacks\n- Use Stack from 'expo-router/stack' for native navigation stacks\n\n### Page Title\n\nSet the page title with `Stack.Title`:\n\n```tsx\n<Stack.Title>Home</Stack.Title>\n```\n\n## Context Menus\n\nAdd long press context menus to Link components:\n\n```tsx\nimport { Link } from \"expo-router\";\n\n<Link href=\"/settings\" asChild>\n  <Link.Trigger>\n    <Pressable>\n      <Card />\n    </Pressable>\n  </Link.Trigger>\n  <Link.Menu>\n    <Link.MenuAction\n      title=\"Share\"\n      icon=\"square.and.arrow.up\"\n      onPress={handleSharePress}\n    />\n    <Link.MenuAction\n      title=\"Block\"\n      icon=\"nosign\"\n      destructive\n      onPress={handleBlockPress}\n    />\n    <Link.Menu title=\"More\" icon=\"ellipsis\">\n      <Link.MenuAction title=\"Copy\" icon=\"doc.on.doc\" onPress={() => {}} />\n      <Link.MenuAction\n        title=\"Delete\"\n        icon=\"trash\"\n        destructive\n        onPress={() => {}}\n      />\n    </Link.Menu>\n  </Link.Menu>\n</Link>;\n```\n\n## Link Previews\n\nUse link previews frequently to enhance navigation:\n\n```tsx\n<Link href=\"/settings\">\n  <Link.Trigger>\n    <Pressable>\n      <Card />\n    </Pressable>\n  </Link.Trigger>\n  <Link.Preview />\n</Link>\n```\n\nLink preview can be used with context menus.\n\n## Modal\n\nPresent a screen as a modal:\n\n```tsx\n<Stack.Screen name=\"modal\" options={{ presentation: \"modal\" }} />\n```\n\nPrefer this to building a custom modal component.\n\n## Sheet\n\nPresent a screen as a dynamic form sheet:\n\n```tsx\n<Stack.Screen\n  name=\"sheet\"\n  options={{\n    presentation: \"formSheet\",\n    sheetGrabberVisible: true,\n    sheetAllowedDetents: [0.5, 1.0],\n    contentStyle: { backgroundColor: \"transparent\" },\n  }}\n/>\n```\n\n- Using `contentStyle: { backgroundColor: \"transparent\" }` makes the background liquid glass on iOS 26+.\n\n## Common route structure\n\nA standard app layout with tabs and stacks inside each tab:\n\n```\napp/\n  _layout.tsx — <NativeTabs />\n  (index,search)/\n    _layout.tsx — <Stack />\n    index.tsx — Main list\n    search.tsx — Search view\n```\n\n```tsx\n// app/_layout.tsx\nimport { NativeTabs } from \"expo-router/unstable-native-tabs\";\nimport { ThemeProvider, DarkTheme, DefaultTheme } from \"expo-router/react-navigation\";\nimport { useColorScheme } from \"react-native\";\n\nexport default function Layout() {\n  const colorScheme = useColorScheme();\n  return (\n    <ThemeProvider value={colorScheme === \"dark\" ? DarkTheme : DefaultTheme}>\n      <NativeTabs>\n        <NativeTabs.Trigger name=\"(index)\">\n          <NativeTabs.Trigger.Icon sf=\"list.dash\" md=\"list\" />\n          <NativeTabs.Trigger.Label>Items</NativeTabs.Trigger.Label>\n        </NativeTabs.Trigger>\n        <NativeTabs.Trigger name=\"(search)\" role=\"search\" />\n      </NativeTabs>\n    </ThemeProvider>\n  );\n}\n```\n\nCreate a shared group route so both tabs can push common screens:\n\n```tsx\n// app/(index,search)/_layout.tsx\nimport { Stack } from \"expo-router/stack\";\nimport { colors } from \"@/theme/colors\";\n\nexport default function Layout({ segment }) {\n  const screen = segment.match(/\\((.*)\\)/)?.[1]!;\n  const titles: Record<string, string> = { index: \"Items\", search: \"Search\" };\n\n  return (\n    <Stack\n      screenOptions={{\n        headerTransparent: true,\n        headerShadowVisible: false,\n        headerLargeTitleShadowVisible: false,\n        headerLargeStyle: { backgroundColor: \"transparent\" },\n        headerTitleStyle: { color: colors.label },\n        headerLargeTitle: true,\n        headerBlurEffect: \"none\",\n        headerBackButtonDisplayMode: \"minimal\",\n      }}\n    >\n      <Stack.Screen name={screen} options={{ title: titles[screen] }} />\n      <Stack.Screen name=\"i/[id]\" options={{ headerLargeTitle: false }} />\n    </Stack>\n  );\n}\n```\n\n## Submitting Feedback\nIf you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:\n```bash\nnpx --yes submit-expo-feedback@latest --category skills --subject \"expo-router\" \"<actionable feedback>\"\n```\nOnly submit when you have something specific and actionable to report. Include as much relevant context as possible.\n","contentSource":"https://raw.githubusercontent.com/expo/skills/main/plugins/expo/skills/expo-router/SKILL.md","contentFetchedAt":"2026-07-28T23:15:38.912Z"}],"featured":true,"official":true,"generatedAt":"2026-07-28T23:15:45.680Z"}