Best practices for Expo mobile projects using React Native, NativeWind, and Supabase.

Install

mkdir -p .claude/skills/expo-mobile && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15536" && unzip -o skill.zip -d .claude/skills/expo-mobile && rm skill.zip

Installs to .claude/skills/expo-mobile

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Expo and React Native patterns for Halvy. Triggers: "component", "screen", "navigation", "expo", "NativeWind", "mobile", "React Native".
136 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Set up Expo SDK managed workflow with Expo Router v3
  • Configure NativeWind v4 for Tailwind CSS syntax
  • Manage explicit dependencies for Expo SDK 54+
  • Verify builds across iOS, Android, and web platforms
  • Structure feature files with components, hooks, and utils
  • Implement Supabase Realtime patterns for data synchronization

How it works

This skill defines project structure, dependency management, and configuration patterns for Expo SDK 54+ managed workflows.

Inputs & outputs

You give it
Project requirements for a mobile application
You get back
Structured Expo mobile project with configured dependencies and patterns

When to use expo-mobile

  • Setting up a new Expo mobile project
  • Configuring NativeWind in Expo
  • Structuring mobile features

About this skill

Expo / React Native Development — Halvy Patterns

Project Setup

  • Expo SDK managed workflow with Expo Router v3
  • NativeWind v4 (Tailwind CSS syntax)
  • Supabase backend
  • TypeScript strict mode
  • FlashList (not FlatList) for all scrollable lists

Explicit Dependencies (SDK 54 — must be listed, never assume transitive)

These are NOT guaranteed as transitive installs — add them explicitly in package.json:

  • babel-preset-expo as a devDependency (pin to ~54.0.x matching SDK version)
  • react-native-worklets — required peer dep of [email protected]; install via npx expo install react-native-worklets
  • react-native-web, react-dom, @expo/metro-runtime — required for web platform support

babel.config.js — Critical Pattern

nativewind/babel returns { plugins: [...] } — it is a preset, not a plugin. Place it in presets[] or Metro will throw: .plugins is not a valid Plugin property

// CORRECT
presets: ['babel-preset-expo', 'nativewind/babel']
plugins: [['module-resolver', { alias: { '@': './src' } }]]

// WRONG — causes silent build failures
plugins: ['nativewind/babel']

Build Verification

tsc and jest do NOT validate Metro/Babel transforms. Always run before merging:

npx expo export --platform ios
npx expo export --platform android
npx expo export --platform web

Zero test files → jest exits 0. This is NOT a build confirmation.

Feature File Structure

src/features/{name}/ components/ — Feature-specific UI components hooks/ — TanStack Query hooks and local state hooks utils/ — Pure functions (no React) tests/ — Integration tests

Critical Rules

  • No window or document — not available in React Native
  • No div/span/p — use View, Text, Pressable from react-native
  • Always handle keyboard avoidance on input screens
  • Always handle safe area insets
  • Always use deep linking for navigable screens
  • Use expo-image over Image for performance
  • FlashList over FlatList for long lists — always
  • All monetary amounts in integer cents — never floats

NativeWind Rules

  • className with Tailwind utilities on all RN components
  • Platform-specific: className="ios:pt-2 android:pt-4"
  • Dark mode: className="bg-white dark:bg-gray-900"
  • Never mix StyleSheet.create with className in the same component
  • Use design tokens from tailwind.config.ts

Screen Pattern

import { ScrollView } from 'react-native' import { Stack } from 'expo-router' import { ErrorBoundary } from '@/components/ErrorBoundary'

export default function FeatureScreen() { return ( <ErrorBoundary> <Stack.Screen options={{ title: 'Feature' }} /> <ScrollView className="flex-1 bg-background"> {/* content */} </ScrollView> </ErrorBoundary> ) }

Supabase Realtime Pattern (Chat)

useEffect(() => { const channel = supabase .channel('chat:' + groupId) .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages', filter: 'group_id=eq.' + groupId, }, handleNewMessage) .subscribe() return () => { supabase.removeChannel(channel) } }, [groupId])

Monetary Arithmetic

// ALWAYS: convert to cents on entry, format on display only const amountCents = Math.round(parseFloat(input) * 100) // NEVER: parseFloat('1.10') + parseFloat('2.20') — float errors

When not to use it

  • When working with React Native without Expo
  • When using FlatList for long lists
  • When mixing StyleSheet.create with className in the same component

Limitations

  • This skill does not support `window` or `document` objects.
  • This skill does not use `div`, `span`, or `p` elements.
  • This skill does not use `FlatList` for long lists.

How it compares

This approach provides specific patterns for Expo development, including NativeWind and Supabase, which is more prescriptive than general React Native guidance.

Compared to similar skills

expo-mobile side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
expo-mobile (this skill)04moReviewIntermediate
react-native-architecture552moReviewAdvanced
react-native-design332moNo flagsIntermediate
heroui-native54moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry