784 words
4 minutes
🌐 How to Host a React Project on Cloudflare Pages with GitHub CI/CD

πŸ“ Step 1: Clone the Template Repository Locally#

NOTE

I’m using a demo repository for this project called fuwari-blog

git clone https://github.com/saicaca/fuwari.git

πŸ“¦ Step 2: Install Dependencies#

Navigate into the project folder and install the dependencies:

cd fuwari
pnpm install

πŸ› οΈ Step 3: Build the Project#

Once dependencies are installed, build the project:

pnpm build
NOTE

We need to build the project to identify the build folder name. I have already built the project and identified the build folder as dist. The output folder Name is important for CI/CD deployment.


πŸ“ Step 4: Create a GitHub Repository with the Following Project File Structure#


πŸ“ 
β”œβ”€β”€ .github/               # GitHub Actions CI/CD workflows
β”‚   └── workflows/
β”‚       └── main.yml       # CI/CD pipeline for deployment
β”œβ”€β”€ .vscode/               # VS Code editor settings
β”œβ”€β”€ public/                # Static assets (images, icons, favicon, etc.)
β”œβ”€β”€ scripts/               # Custom CLI scripts (e.g., post creation)
β”œβ”€β”€ src/                   # Main source directory
β”‚   β”œβ”€β”€ components/        # Reusable UI components
β”‚   β”œβ”€β”€ content/           # Blog content (posts, pages)
β”‚   β”œβ”€β”€ layouts/           # Layout components for pages/posts
β”‚   β”œβ”€β”€ pages/             # Astro routes (e.g., index, about, posts)
β”‚   β”œβ”€β”€ styles/            # Tailwind and custom CSS/SCSS
β”‚   β”œβ”€β”€ config.ts          # Site configuration (title, URL, metadata)
β”‚   └── index.md           # Home page content or root content file
β”œβ”€β”€ .gitattributes         # Git attributes for handling end-of-line configs
β”œβ”€β”€ .gitignore             # Files/directories to ignore in Git
β”œβ”€β”€ .npmrc                 # npm/pnpm registry and config
β”œβ”€β”€ LICENSE                # Project license (MIT)
β”œβ”€β”€ README.md              # Main README file (this one)
β”œβ”€β”€ README.xx.md           # Translated README files (ja-JP, ko, es, zh-CN, th)
β”œβ”€β”€ astro.config.mjs       # Astro project configuration
β”œβ”€β”€ biome.json             # Linter/formatter config (Biome)
β”œβ”€β”€ frontmatter.json       # Frontmatter schema definitions
β”œβ”€β”€ package.json           # Project metadata and dependencies
β”œβ”€β”€ pagefind.yml           # Pagefind (search) configuration
β”œβ”€β”€ pnpm-lock.yaml         # Lockfile for pnpm
β”œβ”€β”€ postcss.config.mjs     # PostCSS configuration
β”œβ”€β”€ svelte.config.js       # Svelte config (if Svelte components used)
β”œβ”€β”€ tailwind.config.cjs    # Tailwind CSS configuration
β”œβ”€β”€ tsconfig.json          # TypeScript configuration
β”œβ”€β”€ vercel.json            # Vercel deployment config
NOTE

All the project files are in the root of the GitHub repo, as shown. I have designed my action file for this project structure. If you plan to put files inside a subfolder, you need to change the GitHub action as needed.

Push your project to a new GitHub repository as shown in the file structure.


βš™οΈ Step 5: Set Up Cloudflare Pages#

  1. Log in to your Cloudflare Dashboard
  2. Navigate to Pages β†’ Click Create Project
Cloudflare Pages UI
  1. Select Direct Upload (we’ll automate with CI/CD)
Cloudflare Direct Upload
  1. Download Cloudfalre Pages Demo by pressing the button, give the project a name, and upload the downloaded demo zip from Cloudflare Temporary.
Cloudflare Pages UI

You can upload a .zip for testing, but GitHub Actions will handle deployment going forward.


βš™οΈ Step 6: GitHub Actions CI/CD Setup#

Create the following file in your GitHub project:

πŸ“ .github/workflows/main.yml

name: Main Deployment

on:
  push:
    branches: [main]
  workflow_dispatch:

env:
  PROJECT_NAME: itsnooblk-blog

jobs:
  Deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20'

      - name: Install pnpm
        run: npm install -g pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build project
        run: pnpm build

      - name: Deploy to Cloudflare Pages
        run: pnpm dlx wrangler pages deploy dist --project-name=${{ env.PROJECT_NAME }}
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.PAGES_DEPLOY_API }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.PAGES_DEPLOY_ACCOUNT }}

variables :

node-version: '20'  : chnage to yournode version
PROJECT_NAME: itsnooblk-blog : your cloudflare project name 

Replace itsnooblk-blog with your actual Cloudflare project name.


πŸ” Step 7: Get Your Cloudflare API Credentials#

πŸ” Example#

Go to your Cloudflare Dashboard β†’ Domain, then copy the URL. It will look something like this:

https://dash.cloudflare.com/2593411e3cce1845dxxxx2b231a9af4/itsnooblk.com

From this URL:

  • Account ID: 2593411e3cce1845dxxxx2b231a9af4
  • Domain: itsnooblk.com
Cloudflare Account ID

πŸ”‘ Step 8: Add GitHub Secrets#

Navigate to your GitHub repository settings:

πŸ‘‰ https://github.com/<your-username>/<repo>/settings/secrets/actions

Add the following secrets:

Secret NameValue
PAGES_DEPLOY_APIYour Cloudflare API Token
PAGES_DEPLOY_ACCOUNTYour Cloudflare Account ID
GitHub Secrets UI

πŸš€ Step 9: Deploy Automatically on Push#

Push your code to trigger the deployment:

git add .
git commit -m "Initial commit"
git push origin main

Track your deployment workflow here: πŸ‘‰ https://github.com/<your-username>/<repo>/actions

GitHub Actions UI

βœ… Step 10: View the Live Site#

Visit your Cloudflare Pages dashboard:

πŸ‘‰ https://dash.cloudflare.com/<account-id>/pages/view/<project-name>

Your site will be hosted on a .pages.dev subdomain by default.

To connect a custom domain:

  1. Go to the Custom Domains tab
  2. Add and verify your domain
Custom Domain Setup

πŸŽ‰ Done!#

🌐 How to Host a React Project on Cloudflare Pages with GitHub CI/CD
https://www.itsnooblk.com/posts/cloudflare-pages-react/
Author
Lahiru Sandaruwan Liyanage
Published at
2025-05-24
License
MIT License