# 🚀 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.*