React Deployment Strategies Guide

Master React deployment across different platforms. Learn how to deploy your React applications to popular hosting platforms with CI/CD pipelines, monitoring, and best practices.

Advertisement Space - top-deployment

Google AdSense: horizontal

Netlify

Static Site HostingEasyFree / Paid

Popular platform for static site hosting with automatic deployments from Git

Best For: Static React apps, SPAs, JAMstack sites

Automatic deployments from GitBuilt-in CI/CDEdge functionsForm handlingCustom domainsSSL certificates

Setup Commands

1# 1. Build your React app
2npm run build
3
4# 2. Install Netlify CLI
5npm install -g netlify-cli
6
7# 3. Login to Netlify
8netlify login
9
10# 4. Deploy from build folder
11netlify deploy --prod --dir=build

Configuration

1# netlify.toml
2[build]
3 publish = "build"
4 command = "npm run build"
5
6[[redirects]]
7 from = "/*"
8 to = "/index.html"
9 status = 200
10
11[build.environment]
12 NODE_VERSION = "20"
13 NPM_VERSION = "10"
14
15# Environment variables
16[context.production.environment]
17 REACT_APP_API_URL = "https://api.example.com"
18
19[context.deploy-preview.environment]
20 REACT_APP_API_URL = "https://staging-api.example.com"

CI/CD Workflow

1# .github/workflows/netlify.yml
2name: Deploy to Netlify
3
4on:
5 push:
6 branches: [ main ]
7 pull_request:
8 branches: [ main ]
9
10jobs:
11 build:
12 runs-on: ubuntu-latest
13
14 steps:
15 - uses: actions/checkout@v3
16
17 - name: Setup Node.js
18 uses: actions/setup-node@v3
19 with:
20 node-version: '20'
21 cache: 'npm'
22
23 - name: Install dependencies
24 run: npm ci
25
26 - name: Run tests
27 run: npm test -- --coverage --watchAll=false
28
29 - name: Build application
30 run: npm run build
31
32 - name: Deploy to Netlify
33 uses: netlify/actions/cli@master
34 with:
35 args: deploy --prod --dir=build
36 env:
37 NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
38 NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

Advantages

  • Easy setup and deployment
  • Automatic SSL certificates
  • Global CDN
  • Branch previews
  • Built-in form handling

Considerations

  • ⚠️Limited server-side capabilities
  • ⚠️Build time limits on free plan
  • ⚠️No database hosting

Vercel

Full-Stack PlatformEasyFree / Paid

Full-stack platform optimized for React and Next.js applications

Best For: Next.js apps, full-stack React applications, serverless functions

Zero-config deploymentsServerless functionsEdge functionsAnalyticsPreview deploymentsAutomatic performance optimization

Setup Commands

1# 1. Install Vercel CLI
2npm install -g vercel
3
4# 2. Login to Vercel
5vercel login
6
7# 3. Deploy from project root
8vercel
9
10# 4. For production deployment
11vercel --prod

Configuration

1// vercel.json
2{
3 "version": 2,
4 "builds": [
5 {
6 "src": "package.json",
7 "use": "@vercel/static-build",
8 "config": {
9 "distDir": "build"
10 }
11 }
12 ],
13 "routes": [
14 {
15 "src": "/(.*)",
16 "dest": "/index.html"
17 }
18 ],
19 "env": {
20 "REACT_APP_API_URL": "https://api.example.com"
21 },
22 "build": {
23 "env": {
24 "NODE_VERSION": "20"
25 }
26 }
27}
28
29// For Next.js (next.config.js)
30/** @type {import('next').NextConfig} */
31const nextConfig = {
32 reactStrictMode: true,
33 swcMinify: true,
34 images: {
35 domains: ['example.com'],
36 },
37 async redirects() {
38 return [
39 {
40 source: '/old-page',
41 destination: '/new-page',
42 permanent: true,
43 },
44 ];
45 },
46};
47
48module.exports = nextConfig;

CI/CD Workflow

1# .github/workflows/vercel.yml
2name: Deploy to Vercel
3
4on:
5 push:
6 branches: [ main ]
7 pull_request:
8 branches: [ main ]
9
10jobs:
11 deploy:
12 runs-on: ubuntu-latest
13
14 steps:
15 - uses: actions/checkout@v3
16
17 - name: Setup Node.js
18 uses: actions/setup-node@v3
19 with:
20 node-version: '20'
21 cache: 'npm'
22
23 - name: Install dependencies
24 run: npm ci
25
26 - name: Run tests
27 run: npm test -- --coverage --watchAll=false
28
29 - name: Build application
30 run: npm run build
31
32 - name: Deploy to Vercel
33 uses: amondnet/vercel-action@v25
34 with:
35 vercel-token: ${{ secrets.VERCEL_TOKEN }}
36 vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
37 vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
38 vercel-args: '--prod'

Advantages

  • Optimized for React/Next.js
  • Serverless functions
  • Edge functions
  • Automatic performance optimization
  • Analytics and monitoring

Considerations

  • ⚠️Vendor lock-in
  • ⚠️Function execution time limits
  • ⚠️Pricing can be expensive for high traffic

AWS S3 + CloudFront

Cloud InfrastructureMediumPay-as-you-go

Scalable cloud hosting with S3 for storage and CloudFront for CDN

Best For: Large-scale applications, enterprise deployments, custom infrastructure

Global CDNHigh availabilityScalable storageCustom caching rulesIntegration with AWS servicesCost-effective for high traffic

Setup Commands

1# 1. Install AWS CLI
2curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
3unzip awscliv2.zip
4sudo ./aws/install
5
6# 2. Configure AWS credentials
7aws configure
8
9# 3. Create S3 bucket
10aws s3 mb s3://my-react-app-bucket
11
12# 4. Enable static website hosting
13aws s3 website s3://my-react-app-bucket --index-document index.html --error-document index.html
14
15# 5. Build and deploy
16npm run build
17aws s3 sync build/ s3://my-react-app-bucket --delete
18
19# 6. Create CloudFront distribution
20aws cloudfront create-distribution --distribution-config file://distribution-config.json

Configuration

1// distribution-config.json
2{
3 "CallerReference": "my-react-app-${Date.now()}",
4 "Origins": {
5 "Quantity": 1,
6 "Items": [
7 {
8 "Id": "S3-my-react-app-bucket",
9 "DomainName": "my-react-app-bucket.s3.amazonaws.com",
10 "S3OriginConfig": {
11 "OriginAccessIdentity": ""
12 }
13 }
14 ]
15 },
16 "DefaultCacheBehavior": {
17 "TargetOriginId": "S3-my-react-app-bucket",
18 "ViewerProtocolPolicy": "redirect-to-https",
19 "MinTTL": 0,
20 "ForwardedValues": {
21 "QueryString": false,
22 "Cookies": {
23 "Forward": "none"
24 }
25 }
26 },
27 "Comment": "React App Distribution",
28 "Enabled": true,
29 "DefaultRootObject": "index.html",
30 "CustomErrorResponses": {
31 "Quantity": 1,
32 "Items": [
33 {
34 "ErrorCode": 404,
35 "ResponsePagePath": "/index.html",
36 "ResponseCode": "200"
37 }
38 ]
39 }
40}
41
42// deploy.js - Deployment script
43const AWS = require('aws-sdk');
44const fs = require('fs');
45const path = require('path');
46const mime = require('mime-types');
47
48const s3 = new AWS.S3({ region: 'us-east-1' });
49const cloudfront = new AWS.CloudFront();
50
51const BUCKET_NAME = 'my-react-app-bucket';
52const DISTRIBUTION_ID = 'E1234567890ABC';
53
54async function uploadToS3(filePath, key) {
55 const fileContent = fs.readFileSync(filePath);
56 const contentType = mime.lookup(filePath) || 'application/octet-stream';
57
58 const params = {
59 Bucket: BUCKET_NAME,
60 Key: key,
61 Body: fileContent,
62 ContentType: contentType,
63 CacheControl: contentType === 'text/html' ? 'no-cache' : 'max-age=31536000'
64 };
65
66 return s3.upload(params).promise();
67}
68
69async function invalidateCloudFront() {
70 const params = {
71 DistributionId: DISTRIBUTION_ID,
72 InvalidationBatch: {
73 CallerReference: `invalidation-${Date.now()}`,
74 Paths: {
75 Quantity: 1,
76 Items: ['/*']
77 }
78 }
79 };
80
81 return cloudfront.createInvalidation(params).promise();
82}
83
84async function deploy() {
85 const buildDir = path.join(__dirname, 'build');
86 // Upload files and invalidate cache
87 console.log('Deployment completed!');
88}
89
90deploy();

CI/CD Workflow

1# .github/workflows/aws-deploy.yml
2name: Deploy to AWS
3
4on:
5 push:
6 branches: [ main ]
7
8jobs:
9 deploy:
10 runs-on: ubuntu-latest
11
12 steps:
13 - uses: actions/checkout@v3
14
15 - name: Setup Node.js
16 uses: actions/setup-node@v3
17 with:
18 node-version: '20'
19 cache: 'npm'
20
21 - name: Install dependencies
22 run: npm ci
23
24 - name: Build application
25 run: npm run build
26
27 - name: Configure AWS credentials
28 uses: aws-actions/configure-aws-credentials@v2
29 with:
30 aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
31 aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
32 aws-region: us-east-1
33
34 - name: Deploy to S3
35 run: |
36 aws s3 sync build/ s3://${{ secrets.S3_BUCKET_NAME }} --delete
37
38 - name: Invalidate CloudFront
39 run: |
40 aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"

Advantages

  • Highly scalable
  • Global CDN
  • Cost-effective for high traffic
  • Full control over infrastructure
  • Integration with AWS ecosystem

Considerations

  • ⚠️Complex setup
  • ⚠️Requires AWS knowledge
  • ⚠️More configuration required
  • ⚠️No built-in CI/CD

GitHub Pages

Static Site HostingEasyFree

Free static site hosting directly from GitHub repositories

Best For: Open source projects, portfolios, documentation sites

Free hostingAutomatic deploymentsCustom domainsHTTPS supportIntegration with GitHubJekyll support

Setup Commands

1# 1. Install gh-pages package
2npm install --save-dev gh-pages
3
4# 2. Add homepage to package.json
5{
6 "name": "my-react-app",
7 "homepage": "https://username.github.io/repository-name",
8 "scripts": {
9 "predeploy": "npm run build",
10 "deploy": "gh-pages -d build"
11 }
12}
13
14# 3. Deploy to GitHub Pages
15npm run deploy
16
17# 4. Enable GitHub Pages in repository settings
18# Go to Settings > Pages > Source: Deploy from a branch > gh-pages

Configuration

1// package.json
2{
3 "name": "my-react-app",
4 "version": "0.1.0",
5 "homepage": "https://username.github.io/my-react-app",
6 "scripts": {
7 "start": "react-scripts start",
8 "build": "react-scripts build",
9 "test": "react-scripts test",
10 "eject": "react-scripts eject",
11 "predeploy": "npm run build",
12 "deploy": "gh-pages -d build"
13 },
14 "devDependencies": {
15 "gh-pages": "^4.0.0"
16 }
17}
18
19// For custom domain (public/CNAME)
20yourdomain.com
21
22// For SPAs - add to public/404.html
23<!DOCTYPE html>
24<html>
25<head>
26 <meta charset="utf-8">
27 <title>Single Page Apps for GitHub Pages</title>
28 <script>
29 var pathSegmentsToKeep = 0;
30 var l = window.location;
31 l.replace(
32 l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
33 l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +
34 l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&/g, '~and~') +
35 (l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +
36 l.hash
37 );
38 </script>
39</head>
40<body>
41</body>
42</html>

CI/CD Workflow

1# .github/workflows/github-pages.yml
2name: Deploy to GitHub Pages
3
4on:
5 push:
6 branches: [ main ]
7 pull_request:
8 branches: [ main ]
9
10permissions:
11 contents: read
12 pages: write
13 id-token: write
14
15concurrency:
16 group: "pages"
17 cancel-in-progress: true
18
19jobs:
20 build:
21 runs-on: ubuntu-latest
22
23 steps:
24 - uses: actions/checkout@v3
25
26 - name: Setup Node.js
27 uses: actions/setup-node@v3
28 with:
29 node-version: '20'
30 cache: 'npm'
31
32 - name: Install dependencies
33 run: npm ci
34
35 - name: Build application
36 run: npm run build
37 env:
38 PUBLIC_URL: /${{ github.event.repository.name }}
39
40 - name: Setup Pages
41 uses: actions/configure-pages@v3
42
43 - name: Upload artifact
44 uses: actions/upload-pages-artifact@v2
45 with:
46 path: './build'
47
48 deploy:
49 environment:
50 name: github-pages
51 url: ${{ steps.deployment.outputs.page_url }}
52 runs-on: ubuntu-latest
53 needs: build
54
55 steps:
56 - name: Deploy to GitHub Pages
57 id: deployment
58 uses: actions/deploy-pages@v2

Advantages

  • Completely free
  • Automatic deployments
  • Custom domains supported
  • SSL certificates
  • Integration with GitHub

Considerations

  • ⚠️Static sites only
  • ⚠️No server-side functionality
  • ⚠️Limited bandwidth
  • ⚠️Public repositories only for free accounts

Docker + Kubernetes

Container PlatformAdvancedVariable

Containerized deployment with orchestration for scalable applications

Best For: Enterprise applications, microservices, scalable infrastructure

Container orchestrationAuto-scalingLoad balancingRolling updatesService discoveryHealth checks

Setup Commands

1# 1. Create Dockerfile
2FROM node:20-alpine as builder
3
4WORKDIR /app
5COPY package*.json ./
6RUN npm ci --only=production
7
8COPY . .
9RUN npm run build
10
11FROM nginx:alpine
12COPY --from=builder /app/build /usr/share/nginx/html
13COPY nginx.conf /etc/nginx/nginx.conf
14
15EXPOSE 80
16CMD ["nginx", "-g", "daemon off;"]
17
18# 2. Build Docker image
19docker build -t my-react-app .
20
21# 3. Run container
22docker run -p 80:80 my-react-app
23
24# 4. Push to registry
25docker tag my-react-app:latest my-registry/my-react-app:latest
26docker push my-registry/my-react-app:latest

Configuration

1# nginx.conf
2events {
3 worker_connections 1024;
4}
5
6http {
7 include /etc/nginx/mime.types;
8 default_type application/octet-stream;
9
10 sendfile on;
11 keepalive_timeout 65;
12
13 server {
14 listen 80;
15 server_name localhost;
16 root /usr/share/nginx/html;
17 index index.html;
18
19 location / {
20 try_files $uri $uri/ /index.html;
21 }
22
23 # Security headers
24 add_header X-Frame-Options "SAMEORIGIN" always;
25 add_header X-Content-Type-Options "nosniff" always;
26 add_header X-XSS-Protection "1; mode=block" always;
27
28 # Caching
29 location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
30 expires 1y;
31 add_header Cache-Control "public, immutable";
32 }
33 }
34}
35
36# kubernetes-deployment.yaml
37apiVersion: apps/v1
38kind: Deployment
39metadata:
40 name: react-app
41spec:
42 replicas: 3
43 selector:
44 matchLabels:
45 app: react-app
46 template:
47 metadata:
48 labels:
49 app: react-app
50 spec:
51 containers:
52 - name: react-app
53 image: my-registry/my-react-app:latest
54 ports:
55 - containerPort: 80
56 resources:
57 requests:
58 cpu: 100m
59 memory: 128Mi
60 limits:
61 cpu: 500m
62 memory: 512Mi
63 livenessProbe:
64 httpGet:
65 path: /
66 port: 80
67 initialDelaySeconds: 30
68 periodSeconds: 10
69 readinessProbe:
70 httpGet:
71 path: /
72 port: 80
73 initialDelaySeconds: 5
74 periodSeconds: 5
75
76---
77apiVersion: v1
78kind: Service
79metadata:
80 name: react-app-service
81spec:
82 selector:
83 app: react-app
84 ports:
85 - protocol: TCP
86 port: 80
87 targetPort: 80
88 type: LoadBalancer
89
90---
91apiVersion: networking.k8s.io/v1
92kind: Ingress
93metadata:
94 name: react-app-ingress
95 annotations:
96 nginx.ingress.kubernetes.io/rewrite-target: /
97spec:
98 rules:
99 - host: myapp.example.com
100 http:
101 paths:
102 - path: /
103 pathType: Prefix
104 backend:
105 service:
106 name: react-app-service
107 port:
108 number: 80

CI/CD Workflow

1# .github/workflows/k8s-deploy.yml
2name: Deploy to Kubernetes
3
4on:
5 push:
6 branches: [ main ]
7
8jobs:
9 deploy:
10 runs-on: ubuntu-latest
11
12 steps:
13 - uses: actions/checkout@v3
14
15 - name: Setup Node.js
16 uses: actions/setup-node@v3
17 with:
18 node-version: '20'
19 cache: 'npm'
20
21 - name: Install dependencies
22 run: npm ci
23
24 - name: Build application
25 run: npm run build
26
27 - name: Build Docker image
28 run: |
29 docker build -t ${{ secrets.DOCKER_REGISTRY }}/my-react-app:${{ github.sha }} .
30 docker tag ${{ secrets.DOCKER_REGISTRY }}/my-react-app:${{ github.sha }} ${{ secrets.DOCKER_REGISTRY }}/my-react-app:latest
31
32 - name: Push to registry
33 run: |
34 echo ${{ secrets.DOCKER_PASSWORD }} | docker login ${{ secrets.DOCKER_REGISTRY }} -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
35 docker push ${{ secrets.DOCKER_REGISTRY }}/my-react-app:${{ github.sha }}
36 docker push ${{ secrets.DOCKER_REGISTRY }}/my-react-app:latest
37
38 - name: Deploy to Kubernetes
39 run: |
40 echo "${{ secrets.KUBECONFIG }}" | base64 -d > kubeconfig
41 export KUBECONFIG=kubeconfig
42 kubectl set image deployment/react-app react-app=${{ secrets.DOCKER_REGISTRY }}/my-react-app:${{ github.sha }}
43 kubectl rollout status deployment/react-app

Advantages

  • Highly scalable
  • Container orchestration
  • Auto-scaling
  • Rolling updates
  • Service discovery
  • Health monitoring

Considerations

  • ⚠️Complex setup
  • ⚠️Requires Kubernetes knowledge
  • ⚠️Higher operational overhead
  • ⚠️More expensive to run

Advertisement Space - bottom-deployment

Google AdSense: horizontal