Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
ofershap avatar

Expo Best Practices

  • 127 installs
  • 1 repo stars
  • Updated February 20, 2026
  • ofershap/expo-best-practices

Helps with ai & agent building tasks.

About

expo-best-practices is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.

  • expo-best-practices
  • AI & Agent Building
  • AI-coding skill

Expo Best Practices by the numbers

  • 127 all-time installs (skills.sh)
  • +4 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #3,734 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ofershap/expo-best-practices --skill expo-best-practices

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs127
repo stars1
Last updatedFebruary 20, 2026
Repositoryofershap/expo-best-practices

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

When to use

Use this skill when working with Expo or React Native code. It teaches current best practices and prevents common mistakes that AI agents make with outdated patterns, manual native setup, and deprecated APIs.

Critical Rules

1. Use Expo Router for navigation

Wrong (agents do this):

import { createStackNavigator } from "@react-navigation/stack";
const Stack = createStackNavigator();
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Correct:

app/
  _layout.tsx
  index.tsx
  settings.tsx

Use the app/ directory convention. Files become routes automatically. New Expo projects include Expo Router by default.

Why: Expo Router is built on React Navigation, provides file-based routing, typed routes, deep linking, and integrates with Expo CLI. Manual React Navigation setup is redundant and misses Expo Router features.

2. Use expo-router layouts for navigation structure

Wrong:

// Each screen manually defines its own layout

Correct:

// app/_layout.tsx
import { Stack } from "expo-router";
export default function RootLayout() {
  return <Stack />;
}

Why: _layout.tsx defines shared navigation structure, tabs, stacks, and nested layouts. It centralizes navigation configuration.

3. Use EAS Build for native builds

Wrong:

expo build:ios
expo build:android

Correct:

eas build --platform ios
eas build --platform android

Why: expo build is deprecated. EAS Build is the current cloud build service with better caching, credentials management, and native module support.

4. Use Expo config plugins for native configuration

Wrong:

# Manually editing
ios/MyApp/Info.plist
android/app/src/main/AndroidManifest.xml

Correct:

// app.config.ts
import { ConfigPlugin } from "expo/config-plugins";
const withMyApiKey: ConfigPlugin<{ apiKey: string }> = (config, { apiKey }) => {
  config = withInfoPlist(config, (c) => {
    c.modResults["MY_API_KEY"] = apiKey;
    return c;
  });
  return config;
};
export default {
  plugins: [["withMyApiKey", { apiKey: process.env.API_KEY }]],
};

Why: Direct edits to native files are overwritten on prebuild. Config plugins modify native files at build time and survive prebuild.

5. Platform-specific code: use platform extensions or Platform.select

Wrong:

if (Platform.OS === "ios") {
  return <IOSComponent />;
}
return <AndroidComponent />;

Correct:

MyComponent.ios.tsx
MyComponent.android.tsx

Or:

import { Platform } from "react-native";
const styles = StyleSheet.create({
  container: Platform.select({
    ios: { paddingTop: 20 },
    android: { paddingTop: 0 },
  }),
});

Why: Platform file extensions let the bundler include only the correct code per platform. Platform.select keeps conditional logic in one file when appropriate.

6. Use expo-image instead of React Native Image

Wrong:

import { Image } from "react-native";
<Image source={{ uri: url }} style={styles.image} />;

Correct:

import { Image } from "expo-image";
<Image source={url} contentFit="cover" style={styles.image} />;

Why: expo-image adds caching, placeholders, blurhash, and better performance. React Native's Image lacks these features.

7. Use expo-font for custom fonts

Wrong:

# Manual font linking via native projects

Correct:

import * as Font from "expo-font";
await Font.loadAsync({
  CustomFont: require("./assets/fonts/CustomFont.ttf"),
});

Why: expo-font handles loading and avoids manual native configuration.

8. Use expo-secure-store for sensitive data

Wrong:

import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.setItem("authToken", token);

Correct:

import * as SecureStore from "expo-secure-store";
await SecureStore.setItemAsync("authToken", token);

Why: AsyncStorage is not encrypted. expo-secure-store uses the platform keychain/Keystore for tokens and secrets.

9. Use expo-notifications for push notifications

Wrong:

// Manual Firebase/APNs setup, native configuration

Correct:

import * as Notifications from "expo-notifications";
const token = await Notifications.getExpoPushTokenAsync();

Why: expo-notifications abstracts push setup across iOS and Android. Manual Firebase/APNs configuration is error-prone and platform-specific.

10. Use app.json or app.config.ts for configuration

Wrong:

# Editing Info.plist or AndroidManifest.xml directly

Correct:

{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "plugins": ["expo-router"]
  }
}

Why: Expo manages native config from app.json/app.config.ts. Direct edits are overwritten on prebuild.

11. Use expo-updates for OTA updates

Wrong:

import codePush from "react-native-code-push";
export default codePush(MyApp);

Correct:

import * as Updates from "expo-updates";
await Updates.checkForUpdateAsync();

Why: expo-updates integrates with EAS and Expo's update service. CodePush requires separate setup and is redundant in Expo projects.

12. Use TypeScript with typed navigation params

Wrong:

router.push("/profile");

Correct:

import { router } from "expo-router";
router.push({ pathname: "/profile/[id]", params: { id: userId } });

Define route params in your route files. Expo Router provides typed route helpers when used with TypeScript.

Why: Typed params prevent runtime errors and improve editor support.

Patterns

  • Create routes under app/ with file names that map to URLs
  • Use _layout.tsx for shared layout, tabs, and stacks
  • Put platform-specific components in Component.ios.tsx and Component.android.tsx
  • Use expo config plugins in app.json / app.config.ts for any native config change
  • Use eas.json for EAS Build profiles

Anti-Patterns

  • Do not set up React Navigation manually in Expo projects
  • Do not use expo build (use EAS Build)
  • Do not edit ios/ or android/ directly in managed workflow
  • Do not use AsyncStorage for auth tokens or secrets
  • Do not use React Native's Image when expo-image is available
  • Do not use CodePush in Expo projects (use expo-updates)

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.