[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build and Ship a Mobile App with Expo and Fastlane

Build and Ship a Mobile App with Expo and Fastlane

Create a cross-platform mobile app with Expo Router for navigation, NativeWind for styling, Reanimated for animations, and Fastlane for automated App Store deployment.

#tailwind#react-native#styling#nativewind#mobile
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 5 skills

Avg quality 90/100·All SAFE
>

expo-router

v

Not yet scored
View skill
>

nativewind

v1.0.0

Use Tailwind CSS in React Native with NativeWind — write className instead of StyleSheet. Use when someone asks to "use Tailwind in React Native", "NativeWind", "style React Native with Tailwind", "className in React Native", or "utility-first styling for mobile". Covers setup, responsive design, dark mode, animations, and platform-specific styles.

93/100 quality
2.39× impact
SAFE
View skill
>

react-native-reanimated

v1.0.0

Build smooth 60fps animations in React Native with Reanimated — run animations on the UI thread without JS bridge delays. Use when someone asks to "animate in React Native", "Reanimated", "smooth mobile animations", "gesture animations", "shared element transitions", or "60fps React Native animations". Covers worklets, shared values, layout animations, gestures, and scroll-driven animations.

87/100 quality
2.26× impact
SAFE
View skill
>

fastlane

v1.0.0

Automate mobile app builds, signing, and deployment with Fastlane — CI/CD for iOS and Android. Use when someone asks to "automate App Store deployment", "Fastlane", "automate iOS build", "CI/CD for mobile", "automate Play Store upload", "code signing automation", or "mobile release pipeline". Covers build automation, code signing, TestFlight, Play Store, screenshots, and CI.

87/100 quality
1.24× impact
SAFE
View skill
>

capacitor

v1.0.0

Turn web apps into native mobile apps with Capacitor — access native device APIs from JavaScript. Use when someone asks to "convert my website to a mobile app", "Capacitor", "web to native app", "access camera from JavaScript", "deploy web app to App Store", "hybrid mobile app", or "Ionic Capacitor". Covers native API access, plugin system, web-to-native bridge, and app store deployment.

93/100 quality
3.21× impact
SAFE
View skill
$

The Problem

Jun's startup built a successful web app and now needs native iOS and Android versions. The team are web developers — they know React and Tailwind but have zero Swift or Kotlin experience. They need navigation (tabs, stacks, modals), platform-native styling, smooth animations, and automated deployment to both app stores. Building two separate native apps is out of budget; they need one codebase that produces quality native apps.

The Solution

Use Expo with Expo Router for file-based navigation (familiar from Next.js), NativeWind for Tailwind-based styling (familiar from web), Reanimated for 60fps animations, and Fastlane to automate builds and App Store/Play Store uploads. The team writes React components with Tailwind classes and gets native apps on both platforms.

Step-by-Step Walkthrough

Step 1: Project Setup

bash
npx create-expo-app@latest my-app --template tabs
cd my-app
npx expo install nativewind tailwindcss react-native-reanimated react-native-gesture-handler
npx tailwindcss init
javascript
// tailwind.config.js
module.exports = {
  content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
  presets: [require("nativewind/preset")],
  theme: {
    extend: {
      colors: {
        brand: { DEFAULT: "#6366F1", light: "#818CF8", dark: "#4F46E5" },
      },
    },
  },
};

Step 2: Navigation with Expo Router

app/
├── _layout.tsx              # Root: auth check + providers
├── (auth)/
│   ├── _layout.tsx          # Auth stack
│   ├── login.tsx            # /login
│   └── signup.tsx           # /signup
├── (tabs)/
│   ├── _layout.tsx          # Tab bar
│   ├── index.tsx            # Home tab
│   ├── search.tsx           # Search tab
│   ├── create.tsx           # Create tab
│   └── profile.tsx          # Profile tab
├── post/
│   └── [id].tsx             # /post/123 (detail screen)
└── settings/
    ├── _layout.tsx          # Settings stack
    ├── index.tsx            # /settings
    └── edit-profile.tsx     # /settings/edit-profile
tsx
// app/_layout.tsx — Root layout with auth redirect
import "../global.css";
import { Stack, Redirect } from "expo-router";
import { useAuth } from "@/hooks/useAuth";

export default function RootLayout() {
  const { user, isLoading } = useAuth();

  if (isLoading) return null;
  if (!user) return <Redirect href="/login" />;

  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="post/[id]" options={{ title: "Post" }} />
      <Stack.Screen name="settings" options={{ title: "Settings" }} />
    </Stack>
  );
}

Step 3: Styled Components with NativeWind

tsx
// components/PostCard.tsx — Styled with Tailwind, animated with Reanimated
import { View, Text, Image, Pressable } from "react-native";
import { Link } from "expo-router";
import Animated, { FadeInDown } from "react-native-reanimated";

interface Post {
  id: string;
  author: { name: string; avatar: string };
  content: string;
  image?: string;
  likes: number;
  timeAgo: string;
}

export function PostCard({ post, index }: { post: Post; index: number }) {
  return (
    <Animated.View
      entering={FadeInDown.delay(index * 80).springify()}
      className="bg-white dark:bg-gray-800 mx-4 my-2 rounded-2xl shadow-sm"
    >
      <Link href={`/post/${post.id}`} asChild>
        <Pressable className="active:opacity-90">
          {/* Author row */}
          <View className="flex-row items-center p-4">
            <Image
              source={{ uri: post.author.avatar }}
              className="w-10 h-10 rounded-full"
            />
            <View className="ml-3 flex-1">
              <Text className="font-semibold text-gray-900 dark:text-white">
                {post.author.name}
              </Text>
              <Text className="text-xs text-gray-500 dark:text-gray-400">
                {post.timeAgo}
              </Text>
            </View>
          </View>

          {/* Content */}
          <Text className="px-4 pb-3 text-gray-700 dark:text-gray-300">
            {post.content}
          </Text>

          {/* Image */}
          {post.image && (
            <Image
              source={{ uri: post.image }}
              className="w-full h-64"
              resizeMode="cover"
            />
          )}

          {/* Actions */}
          <View className="flex-row px-4 py-3 border-t border-gray-100 dark:border-gray-700">
            <Text className="text-gray-500 dark:text-gray-400">
              ❤️ {post.likes} likes
            </Text>
          </View>
        </Pressable>
      </Link>
    </Animated.View>
  );
}

Step 4: Smooth Animations

tsx
// components/LikeButton.tsx — Animated like button with haptics
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  withSequence,
} from "react-native-reanimated";
import { Haptics } from "expo-haptics";
import { Pressable } from "react-native";

export function LikeButton({ isLiked, onToggle }) {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePress = () => {
    scale.value = withSequence(
      withSpring(1.4, { damping: 4 }),
      withSpring(1, { damping: 6 })
    );
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    onToggle();
  };

  return (
    <Pressable onPress={handlePress}>
      <Animated.Text style={animatedStyle} className="text-2xl">
        {isLiked ? "❤️" : "🤍"}
      </Animated.Text>
    </Pressable>
  );
}

Step 5: Automated Deployment with Fastlane

ruby
# fastlane/Fastfile — Automated builds and store uploads
default_platform(:ios)

platform :ios do
  lane :beta do
    increment_build_number(
      build_number: latest_testflight_build_number + 1
    )
    build_app(
      workspace: "ios/MyApp.xcworkspace",
      scheme: "MyApp",
    )
    upload_to_testflight(skip_waiting_for_build_processing: true)
  end
end

platform :android do
  lane :beta do
    gradle(task: "clean bundleRelease", project_dir: "android/")
    upload_to_play_store(
      track: "internal",
      aab: "android/app/build/outputs/bundle/release/app-release.aab",
    )
  end
end
bash
# One command to ship
npx expo prebuild
fastlane ios beta     # → TestFlight
fastlane android beta # → Play Store internal testing

The Outcome

Jun's team ships their first mobile app in 3 weeks — the same timeline it would take to build a single native app in Swift. The web developers write React with Tailwind classes and get iOS + Android apps with native navigation, smooth 60fps animations, and platform-appropriate styling (dark mode adapts to system preference). Fastlane handles the App Store submission dance — code signing, building, uploading, and submitting for review. The app launches with a 4.7-star rating. Total new technology to learn: Expo Router's file conventions (1 day) and Reanimated's shared values (2 days). Everything else is React and Tailwind they already knew.