A modern React Native starter template with Expo 54, featuring Gluestack UI v3 for components, NativeWind v4 for Tailwind CSS styling, and Reanimated v3 for smooth animations.
- Expo 54 - Latest Expo SDK with new architecture support
- Gluestack UI v3 - Beautiful, accessible, and customizable UI components
- NativeWind v4 - Tailwind CSS for React Native
- Reanimated v3 - 60fps animations powered by the native thread
- Expo Router - File-based routing with typed routes
- TypeScript - Full type safety
- Node.js 18+
- iOS Simulator (macOS only) or Android Emulator
- Expo CLI (will be installed with dependencies)
yarn install
# or
npm installyarn start
# or
npm startThis will start the Expo development server. You can then:
- Press
ito open iOS Simulator - Press
ato open Android Emulator - Press
wto open in web browser - Scan the QR code with Expo Go app on your physical device
# iOS
yarn ios
# or npm run ios
# Android
yarn android
# or npm run android
# Web
yarn web
# or npm run web.
├── app/ # Expo Router app directory
│ ├── _layout.tsx # Root layout with providers
│ └── index.tsx # Home screen
├── assets/ # Images, fonts, and other assets
├── app.json # Expo configuration
├── babel.config.js # Babel configuration (includes Reanimated plugin)
├── metro.config.js # Metro bundler configuration
├── tailwind.config.js # Tailwind/NativeWind configuration
├── gluestack-ui.config.ts # Gluestack UI theme configuration
├── global.css # Global Tailwind styles
├── nativewind-env.d.ts # NativeWind type definitions
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies and scripts
The babel.config.js includes both NativeWind and Reanimated plugins:
module.exports = function (api) {
api.cache(true)
return {
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }]],
plugins: [
'nativewind/babel',
// Reanimated plugin must be listed last
'react-native-reanimated/plugin',
],
}
}Important: The Reanimated plugin must always be listed last in the plugins array.
Metro is configured to work with NativeWind v4:
const { getDefaultConfig } = require('expo/metro-config')
const { withNativeWind } = require('nativewind/metro')
const config = getDefaultConfig(__dirname)
module.exports = withNativeWind(config, { input: './global.css' })The app.json includes the Reanimated plugin:
{
"expo": {
"plugins": ["expo-router", "react-native-reanimated/plugin"]
}
}Reanimated v3 may have issues on web. The fix is included in app/_layout.tsx:
// Fix for Reanimated v3 on web
if (typeof window !== 'undefined') {
// @ts-ignore
window._frameTimestamp = null
}Solution: Clear cache and reinstall:
rm -rf node_modules
yarn install
# or npm install
npx expo start --clearSolution: Make sure you import from react-native-reanimated, not react-native:
// âś… Correct
import Animated, {
useSharedValue,
useAnimatedStyle,
} from 'react-native-reanimated'
// ❌ Wrong
import { Animated } from 'react-native'Solutions:
- Make sure
global.cssis imported inapp/_layout.tsx - Clear Metro cache:
npx expo start --clear - Ensure
nativewind-env.d.tsexists for TypeScript support
Make sure CSS variables are defined in global.css:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
/* ... other colors */
}Add nativewind-env.d.ts to your project root:
/// <reference types="nativewind/types" />Solution:
yarn add @gluestack-ui/config
# or
npm install @gluestack-ui/config --saveMake sure your TypeScript is configured correctly:
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "bundler"
}
}# Clear CocoaPods cache
cd ios
rm -rf Pods Podfile.lock
pod install
cd ..# Clear Android build cache
cd android
./gradlew clean
cd ..If you encounter any issues, try clearing all caches:
# Clear watchman
watchman watch-del-all
# Clear Metro bundler cache
npx expo start --clear
# Clear package manager cache
yarn cache clean
# or npm cache clean --force
# Reinstall dependencies
rm -rf node_modules
yarn install
# or npm installThis template supports multiple styling approaches:
<View className="flex-1 bg-background p-4">
<Text className="text-2xl font-bold text-foreground">Hello World</Text>
</View><Box bg="$primary500" p="$4" borderRadius="$lg">
<Heading color="$white">Hello World</Heading>
</Box><Box className="flex-1 bg-card" p="$4">
<Heading className="text-foreground">Best of Both</Heading>
</Box>Basic animation example:
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated'
function MyComponent() {
const scale = useSharedValue(1)
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
}
})
const handlePress = () => {
scale.value = withSpring(scale.value === 1 ? 1.5 : 1)
}
return (
<Animated.View style={animatedStyle}>
<Button onPress={handlePress}>
<ButtonText>Animate</ButtonText>
</Button>
</Animated.View>
)
}Edit gluestack-ui.config.ts:
import { config as defaultConfig } from '@gluestack-ui/config'
export const config = {
...defaultConfig,
tokens: {
...defaultConfig.tokens,
colors: {
...defaultConfig.tokens.colors,
primary500: '#your-color',
},
},
}Edit tailwind.config.js and global.css:
// tailwind.config.js
theme: {
extend: {
colors: {
primary: {
DEFAULT: "hsl(var(--primary))",
},
},
},
}/* global.css */
:root {
--primary: 222.2 47.4% 11.2%;
}yarn start/npm start- Start Expo development serveryarn ios/npm run ios- Run on iOS simulatoryarn android/npm run android- Run on Android emulatoryarn web/npm run web- Run on webyarn lint/npm run lint- Run ESLintyarn type-check/npm run type-check- Run TypeScript type checking
- Kill all Node processes:
killall node - Clear cache:
npx expo start --clear - Restart:
yarn startornpm start
- Clear cache:
npx expo start --clear - For iOS: Rebuild the app (Cmd+R in simulator)
- For Android: Rebuild the app (RR in emulator)
Run type check to see all errors:
yarn type-check
# or
npm run type-check- Expo Documentation
- Gluestack UI Documentation
- NativeWind Documentation
- Reanimated Documentation
- Expo Router Documentation
MIT
Contributions are welcome! Please feel free to submit a Pull Request.