install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/mobile-expo-setup" ~/.claude/skills/intense-visions-harness-engineering-mobile-expo-setup && rm -rf "$T"
manifest:
agents/skills/claude-code/mobile-expo-setup/SKILL.mdsource content
Expo Project Setup
Set up and configure Expo projects with managed workflow, EAS Build, development builds, and config plugins
When to Use
- Starting a new React Native project with Expo
- Migrating from bare React Native to Expo or vice versa
- Configuring EAS Build for cloud-based native builds
- Adding native modules that require config plugins
- Setting up environment-specific configuration (dev, staging, production)
Instructions
- Create a new Expo project with the latest SDK.
npx create-expo-app@latest my-app --template tabs cd my-app
- Use
instead ofapp.config.ts
for dynamic configuration. The TypeScript config allows environment variables, conditional logic, and type safety.app.json
import { ExpoConfig, ConfigContext } from 'expo/config'; export default ({ config }: ConfigContext): ExpoConfig => ({ ...config, name: process.env.APP_ENV === 'production' ? 'MyApp' : 'MyApp (Dev)', slug: 'my-app', version: '1.0.0', orientation: 'portrait', icon: './assets/icon.png', scheme: 'myapp', splash: { image: './assets/splash.png', resizeMode: 'contain', backgroundColor: '#ffffff', }, ios: { supportsTablet: true, bundleIdentifier: 'com.company.myapp', }, android: { adaptiveIcon: { foregroundImage: './assets/adaptive-icon.png', backgroundColor: '#ffffff', }, package: 'com.company.myapp', }, plugins: [ 'expo-router', ['expo-camera', { cameraPermission: 'Allow $(PRODUCT_NAME) to access your camera' }], ], extra: { apiUrl: process.env.API_URL ?? 'https://api.dev.example.com', eas: { projectId: 'your-project-id' }, }, });
- Set up EAS Build for cloud-based native builds. This replaces the classic
service.expo build
npm install -g eas-cli eas login eas build:configure
// eas.json { "cli": { "version": ">= 5.0.0" }, "build": { "development": { "developmentClient": true, "distribution": "internal", "ios": { "simulator": true } }, "preview": { "distribution": "internal" }, "production": { "autoIncrement": true } }, "submit": { "production": { "ios": { "appleId": "you@example.com", "ascAppId": "123456789" }, "android": { "serviceAccountKeyPath": "./google-credentials.json" } } } }
- Use development builds instead of Expo Go for projects with native modules. Development builds include your native code and config plugins, while Expo Go only supports the Expo SDK modules.
# Build for iOS simulator eas build --platform ios --profile development # Build for Android emulator eas build --platform android --profile development # Start the development server npx expo start --dev-client
- Use config plugins to modify native projects without ejecting. Config plugins run at build time to modify
,AndroidManifest.xml
, Gradle files, and Podfiles.Info.plist
// app.config.ts plugins: [ ['expo-camera', { cameraPermission: 'Camera access is needed for scanning' }], ['expo-location', { locationAlwaysAndWhenInUsePermission: 'Allow location for delivery tracking' }], './plugins/withCustomSplash', // Custom config plugin ],
- Use Expo Router for file-based routing. It provides Next.js-style file-system routing for React Native.
app/ _layout.tsx # Root layout index.tsx # Home screen (/) settings.tsx # Settings screen (/settings) [id].tsx # Dynamic route (/:id) (tabs)/ _layout.tsx # Tab layout home.tsx # Tab screen profile.tsx # Tab screen
- Use environment variables with
prefix for client-side values.EXPO_PUBLIC_
# .env.local EXPO_PUBLIC_API_URL=https://api.dev.example.com API_SECRET=server-only # Not exposed to client
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
- Set up TypeScript path aliases for clean imports.
// tsconfig.json { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"] } } }
Details
Managed vs. bare workflow: The managed workflow (default) lets Expo handle native project configuration through config plugins and EAS Build. The bare workflow gives you direct access to
ios/ and android/ directories. Start with managed; eject only if you need native code changes that config plugins cannot handle.
Expo SDK versioning: Each Expo SDK version pins specific React Native and native module versions. Upgrade with
npx expo install --fix to resolve version mismatches. Major SDK upgrades can introduce breaking changes — follow the upgrade guide for each version.
EAS Build vs. local builds: EAS Build runs on Expo's cloud infrastructure — no Xcode or Android Studio needed on your machine. Use local builds (
npx expo run:ios, npx expo run:android) when you need faster iteration or are debugging native code.
Common mistakes:
- Using Expo Go for projects with native modules (native code is not included)
- Hardcoding API URLs instead of using environment variables
- Not running
after adding packages (version mismatches)npx expo install --fix - Forgetting to rebuild after adding a config plugin (config plugins only take effect at build time)
Source
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.