🟫 ClodHost beta
Sign In
🎉 All services free during beta! 🎉 All services free during beta!

Deploying a React App

Build and serve a React frontend on your server. Handle routing, environment variables, and production optimization.

Reading time: 15 min Difficulty: Intermediate
View examples as:
Ask Claude Manual Code

Table of Contents

React Deployment Options

There are two main ways to deploy React:

Recommendation

For most apps, a static build with client-side routing is simpler and faster. Use SSR (Next.js) only if you need SEO for dynamic content.

Creating the React App

Start with a new React project or use your existing one.

New React Project

Example prompt:

"Create a React app for my project using Vite. Include React Router for navigation, and set up a basic structure with Home, About, and Contact pages. Use TypeScript and Tailwind CSS for styling."
# Create new Vite React project
npm create vite@latest my-app -- --template react-ts
cd my-app

# Install dependencies
npm install
npm install react-router-dom

# Install Tailwind (optional)
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Building for Production

Create an optimized build for deployment.

Production Build

Example prompt:

"Build my React app for production. Run the build command and tell me where the output files are. The build should be optimized with minification and code splitting."
# Build the app
npm run build

# Output will be in 'dist' folder (Vite) or 'build' folder (CRA)
# This creates optimized, minified JS/CSS/HTML files

# Preview the build locally
npm run preview

Serving Static Files

Configure your server to serve the built React files.

Nginx Configuration

Example prompt:

"Configure Nginx to serve my React app from /var/www/myapp/dist. Set up proper caching for static assets (JS, CSS, images should cache for 1 year since they have content hashes). Handle client-side routing by serving index.html for all routes."
# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name myapp.com;
    root /var/www/myapp/dist;
    index index.html;

    # Cache static assets (they have content hashes)
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Handle client-side routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;
}

Client-Side Routing

React Router handles navigation in the browser. The server must be configured to support this.

React Router Setup

Example prompt:

"Set up React Router in my app with these routes: / (Home), /about (About), /products (ProductList), /products/:id (ProductDetail), and a 404 page for unknown routes. Add a navigation component that highlights the current page."
// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Navigation } from './components/Navigation';
import { Home, About, Products, ProductDetail, NotFound } from './pages';

function App() {
    return (
        <BrowserRouter>
            <Navigation />
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
                <Route path="/products" element={<Products />} />
                <Route path="/products/:id" element={<ProductDetail />} />
                <Route path="*" element={<NotFound />} />
            </Routes>
        </BrowserRouter>
    );
}
Important

Without proper server configuration, refreshing on a route like /about will return 404. The try_files directive in Nginx (or equivalent) sends all requests to index.html, letting React Router handle them.

Environment Variables

Configure different settings for development and production.

Environment Configuration

Example prompt:

"Set up environment variables for my React app. I need VITE_API_URL to point to http://localhost:3001 in development and https://api.myapp.com in production. Also add VITE_APP_NAME. Show me how to use these in my code."
# .env.development
VITE_API_URL=http://localhost:3001
VITE_APP_NAME=MyApp (Dev)

# .env.production
VITE_API_URL=https://api.myapp.com
VITE_APP_NAME=MyApp

// Usage in React code
const apiUrl = import.meta.env.VITE_API_URL;
const appName = import.meta.env.VITE_APP_NAME;

// Fetch from API
fetch(`${apiUrl}/products`)
    .then(res => res.json())
    .then(data => console.log(data));

Connecting to Your API

Fetch data from your backend API.

API Integration

Example prompt:

"Create an API service module that handles all API calls. Include functions for getProducts, getProduct(id), createProduct, updateProduct, and deleteProduct. Handle loading states, errors, and include the auth token from localStorage in the header."
// services/api.ts
const API_URL = import.meta.env.VITE_API_URL;

async function request(endpoint: string, options: RequestInit = {}) {
    const token = localStorage.getItem('token');

    const response = await fetch(`${API_URL}${endpoint}`, {
        ...options,
        headers: {
            'Content-Type': 'application/json',
            ...(token && { Authorization: `Bearer ${token}` }),
            ...options.headers,
        },
    });

    if (!response.ok) {
        throw new Error(`API Error: ${response.status}`);
    }

    return response.json();
}

export const api = {
    getProducts: () => request('/products'),
    getProduct: (id: string) => request(`/products/${id}`),
    createProduct: (data: Product) => request('/products', {
        method: 'POST',
        body: JSON.stringify(data),
    }),
};

Performance Optimization

Make your React app fast for users.

Lazy Loading Routes

Example prompt:

"Optimize my React app with lazy loading. Split each page into its own bundle that loads only when the user navigates there. Add a loading spinner while the page loads. This should reduce the initial bundle size."
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

// Lazy load pages
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Products = lazy(() => import('./pages/Products'));

function App() {
    return (
        <BrowserRouter>
            <Suspense fallback={<div className="loading">Loading...</div>}>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/products" element={<Products />} />
                </Routes>
            </Suspense>
        </BrowserRouter>
    );
}