Back to Blog

How to Deploy React App on GitHub Pages

Free, fast hosting for your React projects — with GitHub Actions automation and custom domain support.

How to Deploy React App on GitHub Pages

Everything you need to get your React application live on GitHub Pages — from repository setup to custom domains and automated deployments.

1. Prerequisites

Before deploying, make sure you have the following installed and configured on your machine.

RequirementMinimum VersionCheck Command
Node.js16.x or highernode -v
npm8.x or highernpm -v
Git2.xgit --version
GitHub AccountAnygithub.com
# Verify installations
node -v      # Should show v18.x or higher
npm -v       # Should show 9.x or higher
git --version # Should show git version 2.x
Note: If you don't have Node.js installed, download it from nodejs.org. The LTS (Long Term Support) version is recommended for stability.

2. Creating a React App

You can use either Vite (recommended) or Create React App to scaffold your project.

Using Vite

npm create vite@latest my-portfolio -- --template react
cd my-portfolio
npm install

Using Create React App

npx create-react-app my-portfolio
cd my-portfolio

Verify It Works

# Start the dev server
npm run dev    # Vite
npm start      # CRA

# Build for production
npm run build

After running npm run build, you'll see a dist/ folder (Vite) or build/ folder (CRA) containing your production-ready files.

3. Setting Up GitHub Repository

Create a new repository on GitHub and push your code.

Create a New Repository

# Initialize git in your project
git init

# Add all files
git add .

# Commit
git commit -m "Initial commit"

# Rename branch to main
git branch -M main

# Add remote (replace YOUR_USERNAME and REPO_NAME)
git remote add origin https://github.com/YOUR_USERNAME/REPO_NAME.git

# Push to GitHub
git push -u origin main
Repository naming matters: For GitHub Pages, your site will be available at https://YOUR_USERNAME.github.io/REPO_NAME/. If your repo is named YOUR_USERNAME.github.io, it becomes your main GitHub Pages site.

4. Installing gh-pages Package

The gh-pages npm package simplifies deploying to GitHub Pages by creating and pushing to a gh-pages branch.

# Install as dev dependency
npm install --save-dev gh-pages

This package provides a predeploy and deploy script that builds your app and pushes the output to the gh-pages branch automatically.

Why gh-pages? It handles the build-and-deploy workflow in a single command. It creates a separate branch (gh-pages) containing only the built files, keeping your main branch clean.

5. Configuring package.json

Add the homepage field and deployment scripts to your package.json.

For Vite Projects

{
  "name": "my-portfolio",
  "homepage": "https://YOUR_USERNAME.github.io/REPO_NAME",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist"
  },
  "devDependencies": {
    "gh-pages": "^6.0.0"
  }
}

For Create React App Projects

{
  "name": "my-portfolio",
  "homepage": "https://YOUR_USERNAME.github.io/REPO_NAME",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build"
  },
  "devDependencies": {
    "gh-pages": "^6.0.0"
  }
}
Important: The homepage field tells React where the app will be hosted. Without it, asset paths will be wrong and your site will show a blank page.

6. Deploying with GitHub Actions

GitHub Actions provides automated deployment on every push. This is the modern, recommended approach.

.github/workflows/deploy.yml

name: Deploy React to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 18
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build
        env:
          VITE_BASE_URL: /REPO_NAME/

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Enable GitHub Pages in Repository Settings

  1. Go to your repository on GitHub
  2. Click SettingsPages
  3. Under Source, select GitHub Actions
  4. Save the settings
workflow_dispatch: This trigger lets you manually deploy from the Actions tab without pushing new code — useful for re-deploying after configuration changes.

7. Deploying with gh-pages Branch

Alternatively, use the gh-pages package directly from your terminal.

# Deploy in one command
npm run deploy

This runs the predeploy script (builds the app) and then gh-pages -d dist which pushes the dist/ folder to the gh-pages branch.

Manual gh-pages Push

# Build the app
npm run build

# Navigate into the build output
cd dist

# Initialize git
git init
git add -A
git commit -m 'Deploy'

# Push to gh-pages branch
git push -f git@github.com:YOUR_USERNAME/REPO_NAME.git main:gh-pages
GitHub Actions vs gh-pages: GitHub Actions is preferred because it keeps your deployment config in code, runs on GitHub's servers, and doesn't require push access from your local machine.

8. Handling Client-Side Routing

If your React app uses React Router, you need to handle routing on GitHub Pages since it only serves static files.

The Problem

When you navigate to /about on GitHub Pages, it tries to find an about.html file that doesn't exist, resulting in a 404 error.

Solution 1: HashRouter (Easiest)

// Use HashRouter instead of BrowserRouter
import { HashRouter as Router, Routes, Route } from 'react-router-dom'

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/projects" element={<Projects />} />
      </Routes>
    </Router>
  )
}

// URL will be: https://yoursite.github.io/repo/#/about

Solution 2: BrowserRouter with 404.html Redirect

// Add a 404.html redirect (in your public/ folder)
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="refresh" content="0; url=/REPO_NAME/">
    <script>
      window.location.href = '/REPO_NAME/' +
        window.location.pathname.substr(1).replace(/\/$/, '')
    </script>
  </head>
</html>
ApproachProsCons
HashRouterZero config, works immediatelyURLs contain # (ugly)
BrowserRouter + 404.htmlClean URLsExtra file needed, more complex
BrowserRouter + SPA pluginClean URLs, automatic redirectRequires GitHub Actions setup

9. Custom Domain Setup

Use your own domain name instead of the default GitHub Pages URL.

Step 1: Add a CNAME File

# In your public/ or src/ directory, create CNAME file
echo "yourdomain.com" > public/CNAME

Step 2: Configure DNS

At your domain registrar, add these DNS records:

TypeNameValueTTL
A@185.199.108.1533600
A@185.199.109.1533600
A@185.199.110.1533600
A@185.199.111.1533600
CNAMEwwwYOUR_USERNAME.github.io3600

Step 3: Enable in GitHub Settings

  1. Go to repository SettingsPages
  2. Under Custom domain, enter your domain
  3. Check Enforce HTTPS
DNS propagation: It can take up to 24-48 hours for DNS changes to propagate worldwide. Use dig yourdomain.com to check if the records are live.

10. Troubleshooting Common Issues

Blank White Page

// Problem: The homepage field is missing or wrong
// Fix: Ensure package.json has correct homepage
{
  "homepage": "https://username.github.io/repo-name"
}

// Also check your router basename if using BrowserRouter
<BrowserRouter basename="/repo-name">

404 Error on Refresh

// Problem: Client-side routing without server config
// Fix: Use HashRouter or add 404.html redirect

// For Create React App, add this to public/ folder:
// public/redirect.html → rename to 404.html
<meta http-equiv="refresh" content="0;url=/">

Assets Not Loading (CSS/JS 404)

// Problem: Asset paths are absolute instead of relative
// Fix: Don't use absolute paths in your code

// Bad
<img src="/images/logo.png" />

// Good (use relative or process.env.PUBLIC_URL)
<img src={process.env.PUBLIC_URL + "/images/logo.png"} />

// For Vite, use the base config in vite.config.js:
export default defineConfig({
  base: '/REPO_NAME/',
})

Deployment Succeeds But Site Doesn't Update

# Clear your browser cache
# Or use hard refresh: Ctrl+Shift+R (Windows) / Cmd+Shift+R (Mac)

# Check GitHub Pages settings for correct source branch
# gh-pages branch should contain the built files, not source code
Don't commit secrets: Never commit API keys, tokens, or environment variables to your repository. Use GitHub Secrets for CI/CD and .env.local for local development.

Quick Deployment Checklist

  • homepage field set in package.json
  • Build runs without errors (npm run build)
  • Repository is public (or GitHub Pro for private)
  • GitHub Pages source is set to gh-pages branch or GitHub Actions
  • Router configured with correct basename or HashRouter
  • All asset paths are relative (no leading /)
  • No secrets or API keys in code
Back to Top