# 🚀 GitHub → Cloudflare Pages Pipeline

**Date:** July 16, 2026  
**Tags:** Pipelines, CI/CD, GitHub, Cloudflare Pages, Astro, DevOps, AI / Pipelines

---

## 🎯 Overview

This site (the one you are reading) is built by **Astro** and deployed to **Cloudflare Pages** through a **Git-connected pipeline**. There is **no GitHub Actions YAML** and **no `wrangler` config in the repo** — Cloudflare Pages talks directly to the GitHub repository and builds on every push to the production branch.

The whole flow is:

```
   git push origin main
        │  (GitHub receives the push)
        ▼
   Cloudflare Pages  (Git integration, watches )
        │  detects new commit on main
        ▼
   Build container  (Node.js)
        │  runs:  npm install  →  npm run build
        ▼
   dist/  (static output)
        │
        ▼
   Global edge  →  https://personalwebsite-cx5.pages.dev
        │
        ▼
   Production  (pinned to main; preview builds per PR/branch)
```

> ⚠️ **No secrets in the build.** This is a fully static site. All API keys / tokens mentioned in blog content are `` text — none are needed at build time or injected into the build environment.

---

## 🧩 Components

| Component | Role |
|-----------|------|
| **GitHub repo** | `github.com/ryanthemanr0x/PersonalWebsite` (source of truth) |
| **Production branch** | `main` |
| **Cloudflare Pages project** | `personalwebsite` (serves `*.pages.dev` + custom domain) |
| **Framework preset** | Astro (auto-detected from `astro.config.mjs` / `package.json`) |
| **Build command** | `npm run build` (resolves to `astro build`) |
| **Build output** | `dist/` |
| **Node version** | pinned via Cloudflare dashboard / `package.json` engines (Astro 5 needs Node 18.17.1+/20+/22+) |

---

## 🔧 Configuration (what Cloudflare Pages is set to)

Cloudflare Pages is configured with these build settings (set once in the dashboard when the project was created):

```text
Production branch:   main
Build command:      npm run build
Build output dir:   dist
Root directory:     /   (repository root)
Framework preset:   Astro
Node version:          (e.g. 22.x)
```

The repo itself only needs two files for Cloudflare to understand it:

- `package.json` — declares the `build` script (`astro build`) and the Astro dependency.
- `astro.config.mjs` — defines the `site` URL so Astro can build absolute links.

```js
// astro.config.mjs
export default defineConfig({
  site: 'https://personalwebsite.pages.dev',
});
```

```json
// package.json (relevant parts)
{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview"
  },
  "devDependencies": {
    "astro": "^5.0.0"
  }
}
```

---

## 🔄 The Push-to-Live Flow (step by step)

1. **You edit content locally** (e.g. a new blog article under `src/pages/blog/...`).
2. **Commit + push** to `main`:
   ```bash
   git add .
   git commit -m "📝 Add new article"
   git push origin main
   ```
   > 💡 In practice the push uses a token from a secure file (`~/.hermes/scripts/github.txt`) — the remote URL is rewritten to include `` at push time, never committed.
3. **GitHub accepts the push** and notifies connected integrations.
4. **Cloudflare Pages detects** the new `main` commit (webhook from the Git integration).
5. **A build container spins up** with the pinned Node version.
6. **Install:** `npm install` (or `npm ci`) restores `node_modules` from `package-lock.json`.
7. **Build:** `npm run build` → Astro compiles all `.astro` pages → emits static HTML/CSS/JS into `dist/`.
8. **Upload:** Cloudflare uploads `dist/` to its global edge cache.
9. **Go live:** the production URL (`https://personalwebsite-cx5.pages.dev`) now serves the new build. Usually **60–90 seconds** end to end.

---

## 🌿 Preview Builds (branches & PRs)

Cloudflare Pages also builds **every non-production branch / pull request** and gives it a unique preview URL (e.g. `https://.personalwebsite.pages.dev`). This lets you review a change before merging to `main`. Only `main` is promoted to the production domain.

```bash
# Example: test on a branch first
git checkout -b feat/new-section
git commit -am "wip" && git push origin feat/new-section
# -> Cloudflare builds a preview URL for the branch
# merge to main -> production deploy
```

---

## 🩺 Troubleshooting

| Symptom | Likely cause | Fix |
|---------|-------------|-----|
| Build fails immediately | wrong Node version | set `` (Astro 5 needs 18.17.1+/20+/22+) |
| `astro: command not found` | deps not installed | ensure `npm install` step runs (Cloudflare does this automatically) |
| Deploy succeeds but page 404s | wrong output dir | output dir must be `dist` |
| Old content still live | cached / not rebuilt | confirm push landed on `main`; check build log |
| Markdown/JSX parse error | unescaped `<` in article string | escape `<` as `<` or use `"` for quotes (this site's article pattern) |

> 💡 The article pages here use a `const articleHtml = "..."` string rendered with `set:html`. The most common build break is an unescaped character in that string (a literal `"` or a stray backtick). Always build locally (`npm run build`) before pushing to catch it fast.

---

## 🔐 Security Notes

- **No build-time secrets.** Static site; `` tokens in content are just text.
- **Push auth** uses a scoped GitHub PAT (``) from a secure file — never committed to the repo.
- **Cloudflare API token** (if used for manual deploys) stays in the Cloudflare dashboard / account, not in the repo.
- **PR previews** are public URLs — don't put real secrets in branch content you don't intend to expose.

---

## ✅ Summary

The pipeline is deliberately simple: **push to `main` → Cloudflare Pages builds `astro build` → uploads `dist/` to the edge → live in ~60–90s.** No CI YAML, no `wrangler` file, no build secrets — just a Git connection, three build settings (`npm run build`, `dist`, `main`), and Astro doing the rest. Preview builds per branch let you review before promoting. 🚀

---

*No API keys, tokens, or secrets are included — every value is a `` you supply locally. Built with Astro, GitHub, and Cloudflare Pages.*