Loading

How to Host a React App on GitHub Pages, Step by Step

By Manob Editorial ·

How to Host a React App on GitHub Pages, Step by Step

To host a React app on GitHub Pages, set base in vite.config.js to '/your-repo/', push the project to a GitHub repository, and choose GitHub Actions as the source under Settings → Pages. Add a workflow that runs npm ci and npm run build and deploys the dist folder. The site goes live at username.github.io/your-repo.

Steps were checked against GitHub's Pages documentation and Vite's deployment guide (Vite 8.3) on October 14, 2026. We built the example app locally with React 19.3 and React Router 8.4, and tested the routing fix on a local server that, like GitHub Pages, answers unknown paths with 404.html.

What do you need before you start?

  • A GitHub account. GitHub Pages is available in public repositories with GitHub Free, and in public and private repositories with GitHub Pro, Team, Enterprise Cloud and Enterprise Server (GitHub docs).
  • A React app built with Vite. Vite needs Node.js 20.19+ or 22.12+. If your app still uses Create React App, see the FAQ below; if you're starting from a plain HTML template, our HTML to React guide gets you to a Vite app first.
  • Git on your computer, and a committed package-lock.json, because the workflow installs with npm ci.

Step 1: Set the base path in vite.config.js

A project site lives in a sub-folder, https://USERNAME.github.io/REPO/, so every asset URL needs that prefix. Vite adds it at build time when you set base:

// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  base: '/my-react-app/',   // your repository name, with both slashes
})

Use base: '/' (or leave it out) in two cases: a user site, which lives in a repository named USERNAME.github.io, and any site on a custom domain.

Step 2: Push the project to GitHub

Create an empty repository on GitHub named like your base path, then push from the project folder:

git init
git add .
git commit -m "First commit"
git branch -M main
git remote add origin https://github.com/USERNAME/my-react-app.git
git push -u origin main

With the GitHub CLI, one command creates the repository and pushes: gh repo create my-react-app --public --source=. --push. Vite's starter .gitignore already excludes node_modules and dist, which is what you want: GitHub builds the site itself.

Step 3: Choose GitHub Actions as the Pages source

In the repository, open Settings → Pages. Under Build and deployment, set Source to GitHub Actions. Vite's guide explains why: the app needs a build step before there's anything to publish.

Step 4: Add the deploy workflow

Create .github/workflows/deploy.yml. This is Vite's sample workflow with one added step, explained under routing below:

name: Deploy to GitHub Pages

on:
  push:
    branches: ['main']
  workflow_dispatch:

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

concurrency:
  group: 'pages'
  cancel-in-progress: true

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v7
      - name: Set up Node
        uses: actions/setup-node@v7
        with:
          node-version: lts/*
          cache: 'npm'
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Copy index.html to 404.html for client-side routes
        run: cp dist/index.html dist/404.html
      - name: Setup Pages
        uses: actions/configure-pages@v6
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v5
        with:
          path: './dist'
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v5

The versions above were the current major releases of each action on October 14, 2026. Vite's own copy pins each action to a commit SHA instead of a version tag, which is stricter if you want it.

Step 5: Push and check the deployment

git add .github/workflows/deploy.yml
git commit -m "Deploy to GitHub Pages"
git push

Open the Actions tab to watch the run. When it finishes, the deploy job links to the live URL, and Settings → Pages shows the address too. Every later push to main redeploys the site. If a run fails, the log names the step: a failed npm ci usually means the lock file is missing or out of date.

Why is the page blank, or the images broken?

  • Blank page, with 404 errors for /assets/index-….js in the console: the base path is wrong. It must match the repository name exactly, with a slash on each side.
  • Some images missing: Vite rewrites imported images and CSS url() paths, but not a plain string such as src="/img/logo.png" pointing into public/. In our build, that string stayed as written and broke under the sub-folder. Import the image instead, or write src={`${import.meta.env.BASE_URL}img/logo.png`}.

How do you make React Router work on GitHub Pages?

GitHub Pages only serves files that exist. Links inside the app work, but reloading /my-react-app/about or opening it from a bookmark asks the server for a file called about, and GitHub answers with its 404 page. The Create React App deployment docs put it plainly: GitHub Pages doesn't support routers that use the HTML5 history API. You have two fixes.

Option 1: Keep clean URLs with a 404.html copy

Tell the router about the sub-folder with basename, and keep the workflow's copy step, so GitHub's "not found" page is your app:

// src/main.jsx
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <BrowserRouter basename={import.meta.env.BASE_URL}>
    <App />
  </BrowserRouter>,
)

In our test, a direct request for /my-react-app/about loaded 404.html, and the app rendered the About page. The catch: those responses still carry a 404 status, so search engines may not index deep links. That's fine for an app or dashboard, and a problem for a content site that needs every page in Google.

Option 2: Switch to HashRouter

// src/main.jsx
import { createRoot } from 'react-dom/client'
import { HashRouter } from 'react-router'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <HashRouter>
    <App />
  </HashRouter>,
)

URLs become /my-react-app/#/about. React Router's docs say HashRouter keeps the location in the hash "so it is not sent to the server", which means every reload works with no 404 trick. The URLs are less tidy, and the same indexing concern applies.

How do you add a custom domain?

  1. Change base to '/' in vite.config.js, since the site now sits at the domain root, and push.
  2. In Settings → Pages → Custom domain, enter the domain and save. With a GitHub Actions workflow, GitHub's docs say no CNAME file is created, and any existing one is ignored and not required.
  3. At your DNS provider, point www with a CNAME record to USERNAME.github.io, without the repository name. For the bare domain, add A records for GitHub's four addresses: 185.199.108.153, 185.199.109.153, 185.199.110.153 and 185.199.111.153 (custom domain docs).
  4. When the DNS check passes, GitHub requests a certificate from Let's Encrypt. Then tick Enforce HTTPS. GitHub's docs say extra A, AAAA or CNAME records on the same names can stop the certificate from being issued.

Also verify the domain in your GitHub account settings. GitHub's docs say verification stops other GitHub users from using your domain for their own Pages sites. Our guide to connecting a domain to hosting covers checking DNS with dig, and if you don't own a domain yet, see how to buy a domain name.

Is there a way without GitHub Actions?

Yes: the gh-pages package builds on your computer and pushes dist to a gh-pages branch. Install it with npm install gh-pages --save-dev and add two scripts:

"scripts": {
  "predeploy": "npm run build",
  "deploy": "gh-pages -d dist --nojekyll"
}

Run npm run deploy, then set Settings → Pages → Source to Deploy from a branch and pick gh-pages. The --nojekyll flag adds a .nojekyll file so GitHub skips its Jekyll processing. The Actions route is easier to maintain, because the site rebuilds on every push without anyone running a command.

Can you keep API keys in a GitHub Pages app?

No. Vite's env docs say VITE_* variables "should not contain sensitive information such as API keys", because their values are bundled into the JavaScript anyone can download. Anything secret needs a server or a serverless function between the app and the API.

What are GitHub Pages' limits?

From GitHub's Pages limits page, as of October 2026:

  • Published sites can be no larger than 1 GB, and source repositories have a recommended limit of 1 GB.
  • Deployments time out after 10 minutes.
  • Sites have a soft bandwidth limit of 100 GB per month, and a soft limit of 10 builds per hour that doesn't apply to custom Actions workflows like the one above.
  • Pages isn't allowed as free hosting for an online business, an e-commerce site, or a site mainly for commercial transactions or software as a service.

It's also static only: no server code, database or logins of your own. For those, compare the options in our guide to deploying a website. If you build in manob.ai's AI workspace, deploy is included on the free Starter plan, and the Builder plan ($12/month) adds full-stack builds with an API, database and auth, plus a custom domain (plans). Looking for an app to start from? See our React and Next.js template picks.

Frequently asked questions

Is GitHub Pages free for hosting a React app?

Yes, for public repositories on GitHub Free. Publishing from a private repository needs GitHub Pro, Team or Enterprise, and commercial use such as an online store isn't allowed.

Why does my React app show a blank page on GitHub Pages?

Almost always the base path. Set base in vite.config.js to '/repository-name/', exactly matching the repository, then push again.

How do I deploy a Create React App project to GitHub Pages?

Create React App's docs use a "homepage" field in package.json, such as https://myusername.github.io/my-app, with "predeploy": "npm run build" and "deploy": "gh-pages -d build". The React team deprecated Create React App in February 2025, so moving the project to Vite is worth it.

Can I host a Next.js app on GitHub Pages?

Only as a static export: set output: 'export' in next.config.js and deploy the out folder. Next.js lists server-dependent features, including Server Actions, cookies, redirects and default image optimization, as unsupported in that mode.

Does GitHub Pages support HTTPS on a custom domain?

Yes. GitHub's docs say all Pages sites, including correctly configured custom domains, support HTTPS and HTTPS enforcement, with certificates from Let's Encrypt.