How to Deploy a Static Site on GitHub Pages

GitHub Pages hosts static files directly from a repository—ideal when your code already lives on GitHub and you want a free HTTPS URL without introducing another vendor. Official GitHub documentation describes two deployment modes: legacy branch publishing and the modern GitHub Actions upload-pages-artifact workflow. This how-to focuses on the straightforward branch method for LaunchStatic HTML templates, then covers custom domains and when to prefer Cloudflare Pages instead.

Prepare your repository structure

GitHub Pages serves files from the repository root (or /docs if configured). Your index.html must sit at the publishing root. Assets live under predictable paths such as /assets/css/main.css. Use root-relative links so the same HTML works on username.github.io/repo-name/ project pages and apex custom domains.

my-landing/
├── index.html
├── assets/
│   ├── css/main.css
│   └── js/main.js
├── privacy.html
└── robots.txt

For user or organization sites (repo named username.github.io), the site URL is https://username.github.io/. For project sites, URLs include the repo name: https://username.github.io/my-landing/—you may need a <base href> tag or path-prefix-aware links unless you use a custom domain at the root.

Push code to GitHub

Create a public repository (private repos require a paid GitHub plan for Pages in some account types—check current GitHub pricing docs). Initialize git locally and push:

git init
git add .
git commit -m "Initial static site"
git branch -M main
git remote add origin https://github.com/USERNAME/REPO.git
git push -u origin main

Verify files appear in the browser UI before enabling Pages—especially that index.html is not trapped inside a subfolder.

Enable GitHub Pages in repository settings

Open Settings → Pages. Under Build and deployment, set Source to Deploy from a branch. Choose branch main and folder / (root). Save. GitHub provisions HTTPS and a *.github.io URL within a few minutes. Refresh the Pages settings screen until the live link appears.

Optional: deploy with GitHub Actions

If you add a minification or sitemap build step, switch Source to GitHub Actions and commit a workflow file. GitHub's starter static.yml workflow uploads the repository root as an artifact—customize steps before upload.

# .github/workflows/pages.yml
name: Deploy static site
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build   # optional minify/sitemap
      - uses: actions/upload-pages-artifact@v3
        with:
          path: .
      - uses: actions/deploy-pages@v4

Omit the npm line if you have no build. Actions deployments appear in the Actions tab with logs if a step fails.

Configure a custom domain

In Pages settings, add your domain under Custom domain, e.g. www.example.com. GitHub displays required DNS records—typically A records pointing to GitHub's documented IP addresses for apex domains and a CNAME for www targeting username.github.io. Enable Enforce HTTPS once certificate issuance completes (can take up to an hour). Create a CNAME file in your repo root only if documentation still requires it for your setup; the UI often manages records without manual files.

# Optional legacy CNAME file at repo root (single hostname)
www.example.com

Verify forms, analytics, and SEO files

Formspree and Umami work on GitHub Pages because they are browser-side or third-party POST targets. Update Formspree _next redirect URLs to your github.io or custom domain. Confirm robots.txt and sitemap.xml use the live hostname. Run Lighthouse on the deployed URL—GitHub Pages CDN is solid but slower on some regions compared to Cloudflare's edge.

GitHub Pages vs Cloudflare Pages

GitHub Pages excels at simplicity when code is already on GitHub. Cloudflare Pages adds faster global caching, preview deployments per branch, and integrated DNS if you buy domains there. Many teams ship marketing sites on Cloudflare and open-source docs on GitHub Pages—pick one canonical host to avoid duplicate content.

FeatureGitHub PagesCloudflare Pages
Build stepOptional ActionsNative build hook
Custom domain SSLYesYes
BandwidthSoft limits applyGenerous free tier
Best forOSS repos, docsMarketing launches
  • index.html at publishing root
  • Pages enabled on main branch
  • HTTPS loads without certificate warnings
  • Custom domain DNS validated
  • Internal links use correct base path or root-relative URLs

Troubleshooting

404 on project site assets: Paths may need the repo prefix—test with browser Network tab. Actions deploy pending: Ensure permissions include pages: write. HTTPS unavailable: DNS conflicts or CAA records blocking issuance—use GitHub's troubleshooting docs. Old content visible: Hard refresh; GitHub caches aggressively but deploys usually propagate within minutes.

Jekyll and static generator defaults

GitHub Pages historically promoted Jekyll, which ignores folders starting with underscores and processes Liquid templates. Pure HTML repos without a _config.yml bypass Jekyll processing—add an empty .nojekyll file at the root if GitHub mistakenly treats your site as a Jekyll build and excludes paths. This is a common fix when /assets/ returns 404 on Pages but works locally.

# Touch an empty file at repo root
touch .nojekyll

When to migrate to Cloudflare

Consider migrating marketing domains to Cloudflare Pages when you need wildcard previews, edge middleware, or Web Analytics integration without third-party scripts. GitHub Pages remains excellent for open-source documentation mirroring the repo. Many LaunchStatic users deploy production marketing on Cloudflare while keeping GitHub Pages as a mirror—pick one canonical URL and redirect the other to avoid SEO duplication.

Repository visibility and forks

Public repos expose your Formspree IDs and analytics IDs in HTML—rotate them if you fork community templates into production. Private repos on paid GitHub plans can still publish Pages to selected audiences; confirm current GitHub policy before assuming private source means private site. Forks inherit workflows; delete or update .github/workflows files you do not need to avoid failed Action emails on every push.

Related: Custom domain on Cloudflare Cloudflare deploy guide 5-minute Cloudflare deploy Download templates

Is GitHub Pages free for public repos?

Yes for public repositories under standard GitHub free accounts. Confirm current limits in GitHub Pages documentation.

Can I host a single HTML file?

Yes. Put index.html at the publishing root and enable Pages.

Does GitHub Pages run PHP or Node servers?

No. Only static assets and client-side JavaScript. Use external services for forms and APIs.

How do I use a project site at the domain root?

Attach a custom apex domain in Pages settings with the DNS records GitHub provides.

Pick your host and ship

Download a LaunchStatic template, push to GitHub, and enable Pages in settings.

Browse templates Try Cloudflare instead