| title | Deploying to GitHub Pages |
|---|
[[readingTime]]
This site is hosted for free on GitHub Pages and published by GitHub Actions on every push to main. This page explains the setup so you can reproduce it for your own VitePress site.
-
Name the repository
<owner>.github.io(here,binarynoir.github.io). A repository with this name is published athttps://<owner>.github.io/with no sub-path. Any other repository name publishes athttps://<owner>.github.io/<repo>/, and you must then setbase: '/<repo>/'in the VitePress config. -
In the repository, open Settings → Pages and set Source to GitHub Actions. Or from the command line:
gh api repos/<owner>/<repo>/pages -X POST -f build_type=workflow
-
Push to
main. The workflow builds and deploys.
GitHub Pages on a free plan requires a public repository.
<<< @/../.github/workflows/deploy.yml{yaml}
A few choices worth knowing about:
- Least privilege. The workflow asks only for
contents: read,pages: writeandid-token: write. The last one lets the deploy step prove its identity through OIDC. There are no tokens or secrets to manage. fetch-depth: 0. VitePress'slastUpdatedreads each page's git history. A shallow clone would stamp every page with the same date.concurrencywithcancel-in-progress: false. Only one deploy runs at a time, and a deploy that is already running is allowed to finish rather than being cut off halfway.npm ciinstalls exactly whatpackage-lock.jsonsays, so the build matches what you tested locally.- Format check before build. A formatting slip fails the run before anything is published.
- Two jobs.
buildproduces an artifact;deploypublishes it, in thegithub-pagesenvironment, which is what gives the run a visible deployment URL.
ci.yml runs the same checks and build on pull requests but never deploys, so a broken change is caught before it reaches main.
| Symptom | Likely cause |
|---|---|
| Deploy job fails with a Pages 404 or "not enabled" error | Pages Source is not set to GitHub Actions. |
| Site loads but styles and scripts 404 | base does not match the repository name (project sites only). |
| Every page shows the same "Last updated" date | The checkout is shallow. Keep fetch-depth: 0. |
| Build log shows a missing image warning | Image Fallback swapped in a placeholder. On this site that is the intentional demo. |
npm ci fails on a lockfile mismatch |
Run npm install locally and commit the updated package-lock.json. |
Add a docs/public/CNAME file containing your domain, set the same domain under Settings → Pages, and point a DNS record at GitHub. VitePress copies public/ into the build output, so the file travels with every deploy.