React Native

Setting Up a React Native Project in 2025: A Step-by-Step Guide

20250415 0918 React Native 2025 Setup Simple Compose 01jrw4xg39e6vt1vkj765eb26k 1024x683

Introduction

React Native remains one of the most powerful frameworks for building cross-platform mobile apps using JavaScript or TypeScript. Companies like Meta, Microsoft, Shopify, and Discord use React Native to ship iOS and Android apps from a single codebase. In 2025, the ecosystem has matured significantly with the New Architecture (Fabric and TurboModules), improved performance, and better tooling. Whether you’re building for iOS, Android, or even web, setting up your environment properly ensures smooth development from day one. In this comprehensive guide, you’ll learn how to set up a React Native project in 2025 using both Expo and the React Native CLI, including TypeScript configuration, essential libraries, navigation setup, and production-ready folder structure.

Expo vs React Native CLI: Which to Choose

Before diving into setup, understand the trade-offs:

Feature Expo React Native CLI
Setup time 5 minutes 30+ minutes
Native code access Via config plugins Full access
OTA updates Built-in Manual setup
Build service EAS Build Local or CI
Web support Built-in Manual setup
Custom native modules Supported (dev builds) Full control

Recommendation: Start with Expo unless you have specific native module requirements that Expo doesn’t support. You can always “eject” or use development builds later.

Option 1: Setting Up with Expo

Prerequisites

# Check Node.js version (18+ recommended)
node -v

# Install/update npm
npm install -g npm@latest

Create the Project

# Create a new Expo project with TypeScript
npx create-expo-app@latest MyApp --template blank-typescript

# Navigate to project
cd MyApp

# Start development server
npx expo start

Scan the QR code with the Expo Go app on your phone, or press i for iOS simulator, a for Android emulator.

Install Essential Dependencies

# Navigation
npx expo install @react-navigation/native @react-navigation/native-stack
npx expo install react-native-screens react-native-safe-area-context

# State management
npm install zustand

# Data fetching
npm install @tanstack/react-query axios

# Forms
npm install react-hook-form zod @hookform/resolvers

# UI components
npx expo install expo-linear-gradient
npm install react-native-reanimated

# Storage
npx expo install @react-native-async-storage/async-storage
npx expo install expo-secure-store

Configure TypeScript

// tsconfig.json
{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@screens/*": ["src/screens/*"],
      "@hooks/*": ["src/hooks/*"],
      "@utils/*": ["src/utils/*"]
    }
  },
  "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
// babel.config.js - Enable path aliases
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        'module-resolver',
        {
          root: ['./'],
          alias: {
            '@': './src',
            '@components': './src/components',
            '@screens': './src/screens',
            '@hooks': './src/hooks',
            '@utils': './src/utils',
          },
        },
      ],
      'react-native-reanimated/plugin', // Must be last
    ],
  };
};

Option 2: Setting Up with React Native CLI

Prerequisites

# macOS
brew install node watchman

# iOS development requires:
# - Xcode from App Store
# - Xcode Command Line Tools: xcode-select --install
# - CocoaPods: sudo gem install cocoapods

# Android development requires:
# - Android Studio
# - Android SDK (API 33+)
# - ANDROID_HOME environment variable set

Create the Project

# Create with TypeScript template
npx react-native@latest init MyApp --template react-native-template-typescript

cd MyApp

# Install iOS dependencies
cd ios && pod install && cd ..

# Run on iOS
npx react-native run-ios

# Run on Android
npx react-native run-android
// android/gradle.properties
newArchEnabled=true

// ios/Podfile - Uncomment this line:
# :fabric_enabled => true
# Rebuild after enabling
cd ios && pod install && cd ..
npx react-native run-ios

Production-Ready Folder Structure

src/
├── app/                    # App entry and providers
│   ├── App.tsx
│   └── providers.tsx
├── components/             # Shared components
│   ├── ui/
│   │   ├── Button.tsx
│   │   ├── TextField.tsx
│   │   └── Card.tsx
│   └── layout/
│       ├── Screen.tsx
│       └── Header.tsx
├── config/                 # Configuration
│   ├── api.ts
│   ├── constants.ts
│   └── theme.ts
├── features/               # Feature modules
│   ├── auth/
│   │   ├── screens/
│   │   ├── hooks/
│   │   ├── api/
│   │   └── store/
│   ├── home/
│   └── profile/
├── hooks/                  # Shared hooks
│   ├── useAuth.ts
│   └── useApi.ts
├── navigation/             # Navigation setup
│   ├── RootNavigator.tsx
│   ├── AuthNavigator.tsx
│   └── types.ts
├── stores/                 # Global state
│   └── authStore.ts
├── types/                  # Shared types
│   └── api.ts
└── utils/                  # Utilities
    ├── storage.ts
    └── validators.ts

Setting Up Navigation

// src/navigation/types.ts
export type RootStackParamList = {
  Auth: undefined;
  Main: undefined;
};

export type AuthStackParamList = {
  Login: undefined;
  Register: undefined;
  ForgotPassword: undefined;
};

export type MainTabParamList = {
  Home: undefined;
  Profile: undefined;
  Settings: undefined;
};

// src/navigation/RootNavigator.tsx
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useAuthStore } from '@/stores/authStore';
import { AuthNavigator } from './AuthNavigator';
import { MainNavigator } from './MainNavigator';
import type { RootStackParamList } from './types';

const Stack = createNativeStackNavigator();

export function RootNavigator() {
  const isAuthenticated = useAuthStore((state) => state.isAuthenticated);

  return (
    
      
        {isAuthenticated ? (
          
        ) : (
          
        )}
      
    
  );
}

App Entry Point

// src/app/providers.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { ReactNode } from 'react';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 2,
      staleTime: 1000 * 60 * 5, // 5 minutes
    },
  },
});

export function AppProviders({ children }: { children: ReactNode }) {
  return (
    
      
        
          {children}
        
      
    
  );
}

// src/app/App.tsx
import { StatusBar } from 'expo-status-bar';
import { AppProviders } from './providers';
import { RootNavigator } from '@/navigation/RootNavigator';

export default function App() {
  return (
    
      
      
    
  );
}

VS Code Configuration

// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "typescript.preferences.importModuleSpecifier": "non-relative"
}

// .vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "msjsdiag.vscode-react-native",
    "dsznajder.es7-react-js-snippets",
    "bradlc.vscode-tailwindcss"
  ]
}

Common Mistakes to Avoid

Skipping TypeScript: TypeScript catches bugs early and improves IDE support. Always use it for production apps.

Flat folder structure: Dumping everything in components/ doesn’t scale. Use feature-based organization.

Not configuring path aliases: Relative imports like ../../../components are hard to maintain. Set up @/ aliases.

Missing gesture handler setup: Many libraries require GestureHandlerRootView at the root. Add it early.

Ignoring the New Architecture: Enable Fabric and TurboModules for better performance in new projects.

Conclusion

React Native setup in 2025 is more streamlined than ever. Expo provides the fastest path to production with built-in OTA updates, EAS Build, and excellent developer experience. The React Native CLI offers full control when you need custom native code. Either way, invest time in proper TypeScript configuration, path aliases, and folder structure from day one—it pays dividends as your project grows. The essential stack includes React Navigation for routing, Zustand or Redux for state, React Query for server state, and React Hook Form for forms. With this foundation, you’re ready to build production-quality mobile apps. For more on structuring your React Native project, check out our guide on Cross-Platform Project Structure. For the latest React Native features, explore the official documentation.

Leave a Comment