← All Articles

Deploying a Portfolio Site with Cloudflare Pages and GitHub: A Practical Workflow

By Janith Rathnayake · Web Deployment · Updated July 2026

janidesh.pages.dev runs on Cloudflare Pages, connected directly to a GitHub repo — push to main, and the live site updates a minute or two later with no manual upload step. It's a simple pipeline once it's set up correctly, but I hit a few avoidable snags getting there that are worth writing down.

1. Why Cloudflare Pages for a static/portfolio site

For a site that's mostly static HTML/CSS/JS with the occasional client-side AI integration, Cloudflare Pages hits a good balance: free hosting on a global CDN, automatic HTTPS, git-based deploys, and none of the cold-start latency you'd get from a serverless function-based host for content that doesn't need a server at all. The trade-off is that anything requiring persistent server-side state needs a separate backend (I run that piece on Render for projects that need it) — Pages itself is front-end only unless you're using Cloudflare Functions for light server-side logic.

2. The connection setup

  1. Push the site to a GitHub repository (public or private both work).
  2. In the Cloudflare dashboard, create a new Pages project and connect it to that repo.
  3. Set the build output directory. For a plain static site with no build step, this is just the repo root (or whichever folder holds index.html) — leave the build command empty.
  4. Every push to the connected branch triggers an automatic deploy; pull requests get their own preview URLs, which is genuinely useful for testing changes before they go live.

3. The repo-size mistake

Early on, a deploy started failing with the repo flagged as too large. The instinct is to assume it's the actual site assets (images, video backgrounds) — but the real cause was node_modules and a Python .venv folder that had been committed by accident from unrelated tooling used during development. Neither belongs in a deployed static site, and both bloat the repo far more than any image asset would.

Fix: add a proper .gitignore before the first commit, not after — node_modules/, .venv/, __pycache__/, and any local build artifacts should never reach the repo. If they already have, they need to be purged from git history (not just deleted in a new commit) or the repo stays bloated.

4. Asset organization that scales

Once the AI portfolio pieces (3D scenes, video backgrounds, texture libraries) started growing, flat folder structure stopped working. What held up:

5. Custom domains and DNS

Cloudflare Pages gives a free *.pages.dev subdomain by default, which is enough for most portfolio use cases. If pointing a custom domain at it, the DNS side is handled inside the same Cloudflare dashboard if the domain is already on Cloudflare — a CNAME record pointing at the Pages project, with SSL handled automatically. The main gotcha is DNS propagation delay right after the switch, which looks like a broken deploy but is actually just DNS catching up.

Takeaways

The git-based deploy model is close to zero-maintenance once it's set up right, but "set up right" means a real .gitignore from commit one, deliberate asset organization before the project grows, and compressed media before it ever touches the repo. Nearly every deployment headache I've had traced back to one of those three being skipped early and paid for later.