Skip to content
Home
React Deployment: Vercel, Netlify, Docker, and CI/CD

React Deployment: Vercel, Netlify, Docker, and CI/CD

React React 8 min read 1673 words Beginner ExcellentWiki Editorial Team

Deploying a React application involves build optimization, environment configuration, and choosing the right hosting platform. Unlike traditional server-rendered apps, React applications are typically static files (HTML, JavaScript, CSS) that can be served from a CDN. However, frameworks like Next.js add server-side rendering and API routes that require Node.js servers.

Build Optimization for Production

Before deploying, optimize your React application for production:

Production Build

npm run build

Create React App, Vite, and Next.js all generate optimized production builds. Vite uses Rollup for tree-shaking and code splitting. Next.js applies automatic optimizations including image optimization, script loading strategies, and font inlining.

Environment Variables

React applications embed environment variables at build time (variables prefixed with REACT_APP_ in CRA, VITE_ in Vite, NEXT_PUBLIC_ in Next.js):

NEXT_PUBLIC_API_URL=https://api.example.com npm run build

Important: Build-time variables are embedded in the JavaScript bundle and visible to clients. Never store secrets in client-side environment variables. Use server-side environment variables (accessed through API routes or Server Components) for sensitive values.

Bundle Analysis

Use @next/bundle-analyzer for Next.js or vite-plugin-visualizer for Vite to identify large dependencies and code splitting opportunities:

// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
module.exports = withBundleAnalyzer({});

Hosting Platforms

Vercel

Vercel, created by the team behind Next.js, is the most popular hosting platform for React applications. It provides:

  • Zero-configuration deployment for Next.js, Vite, and CRA
  • Automatic preview deployments for every git branch
  • Edge Functions for running code at CDN edge locations
  • Analytics for real-time performance monitoring
  • Serverless functions for API routes
npx vercel --prod

Vercel automatically detects the framework and configures build settings. The live output is served from Vercel’s global CDN (100+ locations).

Netlify

Netlify is a strong alternative, particularly for static React applications:

  • Continuous deployment from Git repositories
  • Netlify Functions for serverless backend logic
  • Split testing for A/B testing deployments
  • Form handling without a backend server

For client-side routing (React Router), configure a _redirects file:

/*    /index.html   200

This ensures that all paths serve index.html so React Router can handle routing on the client side.

Static Hosting (AWS S3 + CloudFront)

For enterprise deployments, AWS S3 with CloudFront provides maximum control:

  1. Build the React app
  2. Upload to S3 bucket
  3. Configure CloudFront CDN
  4. Set error document to index.html for SPA routing

This approach scales to any traffic level and integrates with AWS services (Cognito for auth, Lambda for APIs).

Docker Deployment

Docker provides consistent builds across environments. A multi-stage Dockerfile for a Vite or CRA React app:

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

For Next.js, use the official Docker example from the Next.js repository, which handles standalone output mode:

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

CI/CD Pipelines

GitHub Actions

A typical GitHub Actions workflow for React deployment:

name: Deploy
on: push to main
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npm test
      - run: npm run build
      - uses: peaceiris/actions-gh-pages@v3
        with: { publish_dir: ./dist }

For Vercel or Netlify, use their official GitHub Actions for deployment:

- uses: amondnet/vercel-action@v25
  with:
    vercel-token: ${{ secrets.VERCEL_TOKEN }}
    vercel-org-id: ${{ secrets.ORG_ID}}
    vercel-project-id: ${{ secrets.PROJECT_ID }}

Environment Variables and Secrets Management

Managing environment variables across multiple environments requires careful organization. Next.js supports .env.local for local development, .env.production for production builds, and .env.development for development servers. Vite uses .env.development and .env.production. The precedence order is:

  1. Environment variables set at runtime in CI/CD (highest priority)
  2. .env.{environment}.local
  3. .env.{environment}
  4. .env.local
  5. .env (lowest priority)

For secrets, use your hosting platform’s built-in secret management. Vercel provides Environment Variables in the project settings with encryption at rest. GitHub Actions uses repository secrets encrypted in the Actions secrets store. Never commit .env files containing secrets to version control — add them to .gitignore.

Environment Management

Manage multiple environments (development, staging, production) with separate environment files and CI/CD pipelines:

.development.env  # REACT_APP_API_URL=http://localhost:4000
.staging.env      # REACT_APP_API_URL=https://staging-api.example.com
.production.env   # REACT_APP_API_URL=https://api.example.com

Use GitHub Environments or Vercel’s built-in environment management to control which variables apply to each deployment.

Deployment Strategies

Different projects require different deployment strategies:

Static Export

For client-rendered React apps (CRA, Vite), the build output is a folder of static files. Deploy these to any static host:

npm run build   # outputs to dist/ or build/

Static deployments are the simplest, cheapest, and most scalable. They handle traffic spikes automatically when served from a CDN.

Server-Side Rendering

Next.js applications with SSR require a Node.js runtime. Vercel handles this automatically. For custom servers, the next start command runs the production server. Dockerize the application for container orchestration platforms:

FROM node:20-alpine
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
COPY .next/standalone ./
COPY public ./public
USER nextjs
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "server.js"]

Incremental Static Regeneration

ISR combines static generation with server capabilities. Pages are pre-rendered at build time and revalidated on demand. This strategy works well for content-heavy sites that need frequent updates without full rebuilds.

Staging and Preview Deployments

Preview deployments give every pull request a unique URL for review before merging to production:

# Each PR gets: https://pr-123--app-name.vercel.app
# Netlify: https://deploy-preview-123--app-name.netlify.app

Preview deployments enable QA teams and stakeholders to review changes in a production-like environment. They catch visual regressions, configuration errors, and integration issues before they reach production users. They also serve as live documentation for pull requests, making code reviews more effective. GitHub integrates preview URLs directly into PR status checks.

For staging environments, mirror production infrastructure at a smaller scale. Use the same database schema, same CDN configuration, and same environment variables (with staging-specific secrets). The closer staging mirrors production, the fewer surprises during production deployments.

CI/CD Pipeline Best Practices

A well-designed CI/CD pipeline prevents deployment failures and rollbacks:

name: CI/CD
on: [push]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm ci && npm run lint
  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm ci && npm test -- --coverage
  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
    steps:
      - run: npm ci && npm run build
  deploy:
    needs: [build]
    if: github.ref == 'refs/heads/main'
    steps:
      - run: vercel --prod

Key principles:

  • Fail fast: Run linting and type checking before build and test
  • Cache dependencies: actions/cache for node_modules speeds up subsequent runs
  • Preview deployments: Deploy every PR to a unique URL for review
  • Environment parity: Use Docker or the same Node.js version across development, staging, and production to prevent environment-specific bugs
  • Rollback strategy: Vercel and Netlify support instant rollbacks to any previous deployment

Monitoring and Error Tracking

Post-deployment monitoring is essential:

  • Sentry: Error tracking with React integration via @sentry/react
  • Datadog / New Relic: Full observability (APM, logs, traces)
  • Vercel Analytics: Built-in web analytics for Vercel-deployed apps
  • LogRocket: Session replay for debugging user issues
import * as Sentry from '@sentry/react';
Sentry.init({ dsn: process.env.SENTRY_DSN });

React Performance Best Practices

Performance optimization in React requires understanding when and why components re-render. React re-renders a component when its state changes, its parent re-renders, or the context it consumes changes. Unnecessary re-renders are the most common performance issue. Use React.memo to prevent re-renders when props have not changed — it performs a shallow comparison of props and skips rendering if they are identical. The useMemo hook memoizes expensive computation results, recalculating only when dependencies change. The useCallback hook memoizes function references, preventing child components from re-rendering due to new function references on every parent render. For lists, ensure each item has a stable, unique key prop — using array indices as keys causes bugs when items are reordered. Virtualization libraries like react-window and react-virtuoso render only visible items in long lists, dramatically reducing DOM nodes. Code splitting with React.lazy and Suspense loads components on demand, reducing initial bundle size. Profile your application with React DevTools Profiler before optimizing — measuring identifies actual bottlenecks that are worth fixing.

Testing React Components Effectively

React Testing Library encourages testing from the user’s perspective. Write tests that verify behavior, not implementation details. Use getByRole, getByLabelText, and getByText queries to find elements the way users do — by accessibility attributes and visible text. Avoid testing internal state or component internals; instead, test what the user sees and does. For async operations, use waitFor and findBy queries that retry until the element appears. Mock external dependencies at the network level using MSW (Mock Service Worker) rather than mocking imported modules. This creates more realistic tests that verify your integration with actual API contracts.

FAQ

Should I use static hosting or a server for my React app?

Use static hosting (Vercel, Netlify, S3) if your app is a client-rendered SPA. Use a Node.js server or serverless platform if you need SSR, API routes, or middleware. Next.js apps typically deploy to Vercel or a custom Node.js server.

How do I handle client-side routing on static hosts?

Configure the host to serve index.html for all paths. On Netlify, use a _redirects file. On Vercel, this is automatic. On S3/CloudFront, set the error document to index.html.

What is the best way to manage environment variables?

Use a CI/CD pipeline that injects environment variables at build time. Never commit secrets to Git. Use Vercel’s or Netlify’s built-in environment variable management for simple setups.

Do I need a CDN for my React app?

Yes. Static React apps benefit from CDN distribution for global latency reduction. Vercel, Netlify, and CloudFront all include CDN delivery.

Conclusion

Deploying React applications ranges from simple static hosting to complex Docker-based CI/CD pipelines. Start with Vercel (for Next.js) or Netlify (for CRA/Vite) for zero-configuration deployment. Add Docker for consistency, CI/CD for automation, and monitoring for production visibility. The platforms’ official documentation and the Next.js deployment guide are essential resources. For build tooling and framework choice, see Next.js Guide, and for environment-related patterns, see React Ecosystem.

For a comprehensive overview, read our article on Next Js Guide.

For a comprehensive overview, read our article on React Authentication.

Section: React 1673 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top