GitHub Pages — Deploy a Site for Free
What GitHub Pages Is
GitHub Pages is a free static site hosting service built into GitHub. You configure which branch and folder to serve, and GitHub automatically builds and publishes your content to a URL under the github.io domain. Changes to your repository are reflected on the live site within seconds to minutes.
"Static site" means the server serves HTML, CSS, and JavaScript files directly — there is no server-side processing, no database, and no backend runtime. Every visitor receives the same pre-built files. This is perfectly suitable for:
- Personal portfolios and developer profiles
- Documentation sites for open source projects
- Landing pages for apps or products
- Course materials and tutorials
- Project showcases
GitHub Pages is free for public repositories. Private repositories require a GitHub Pro or organization plan. There are limits: 1 GB repository size, 1 GB monthly bandwidth, and a soft limit of 10 builds per hour — all generous for typical static sites.
Two Types of GitHub Pages Sites
User/Organization Sites
A user site is published at https://yourusername.github.io. It is created from a repository named exactly yourusername.github.io (where yourusername matches your GitHub username exactly, case-insensitively).
For organizations, an organization site is published at https://yourorgname.github.io from a repository named yourorgname.github.io.
Key characteristics:
- The site URL is the root domain (no subdirectory)
- The source must be the
mainormasterbranch (no other branch options) - You can only have one user/org site per account
Project Sites
A project site is published at https://yourusername.github.io/repository-name. It can be created from any repository and from any branch or folder you choose.
For example, if your username is alice and your repository is my-portfolio:
- The site is at
https://alice.github.io/my-portfolio - You can use
main,gh-pages, or any other branch - You can serve from the root
/or from the/docsfolder
Most developers have one user site and potentially many project sites — one per open source project they maintain.
Enabling GitHub Pages
From a Branch
- Go to your repository → Settings → Pages
- Under Source, select Deploy from a branch
- Select the branch (
main,gh-pages, etc.) - Select the folder: / (root) or /docs
- Click Save
GitHub will show "Your site is live at https://username.github.io/repo" within a minute or two. A deployment entry appears in the Actions tab under the "pages build and deployment" workflow.
From the /docs Folder
Many projects use a /docs folder in their main branch rather than a separate gh-pages branch. This approach keeps documentation colocated with the code that it documents:
In Settings → Pages, select branch main and folder /docs.
The gh-pages Branch Approach
Many older tools (and some static site generators) push the built output to a dedicated gh-pages branch, keeping the source code on main and the build artifacts separate:
The gh-pages npm package automates this for Node-based sites:
Add to package.json:
Run npm run deploy and the build output is pushed to the gh-pages branch and published.
Deploying a Simple HTML/CSS Site
Let us build and deploy a minimal personal portfolio page from scratch.
Step 1: Create the Repository
Create a new repository on GitHub named yourusername.github.io (replace with your actual username). Initialize with a README.
Step 2: Create the HTML and CSS
Step 3: Commit and Push
Step 4: Enable Pages
In the repository settings, navigate to Pages, select branch main, folder / (root), and save.
Visit https://yourusername.github.io in 1-2 minutes.
Custom Domain Setup
GitHub Pages supports custom domains — you can serve your site from yourdomain.com instead of yourusername.github.io.
Step 1: Add the Custom Domain in GitHub
In Settings → Pages → Custom domain, enter your domain (e.g., alexchen.dev) and click Save. GitHub creates a CNAME file in your repository root.
Step 2: Configure DNS
Depending on whether you are using an apex domain (example.com) or a subdomain (www.example.com):
For an apex domain, add A records in your DNS provider pointing to GitHub's IP addresses:
Also add an AAAA record for IPv6 (optional but recommended):
For a subdomain (e.g., www.alexchen.dev), add a CNAME record:
Step 3: Enforce HTTPS
After DNS propagates (can take up to 48 hours, usually faster), return to Settings → Pages and check Enforce HTTPS. GitHub automatically provisions a TLS certificate via Let's Encrypt.
The CNAME File
The CNAME file in your repository root contains your custom domain. It must contain exactly one line — your domain name:
If you delete this file, the custom domain association is removed. Keep it committed.
Deploying with GitHub Actions
Deploying from a branch is simple but limiting — you cannot run a build step. If your site uses a static site generator (Jekyll, Hugo, Eleventy, Astro, Next.js static export), you need GitHub Actions to build the site first and then deploy the output.
Setting Up Actions Deployment
In Settings → Pages → Source, select GitHub Actions instead of a branch.
GitHub provides starter workflows for popular generators. Here is a complete workflow for deploying a Vite/static build:
Save this as .github/workflows/deploy.yml. Every push to main now triggers a build and deployment.
Key Actions Used
- actions/upload-pages-artifact — packages your build output into a GitHub Pages artifact
- actions/deploy-pages — deploys the artifact to GitHub Pages (requires
pages: writeandid-token: writepermissions)
Jekyll on GitHub Pages
GitHub Pages has native Jekyll support — if your repository contains a Jekyll project (with a _config.yml), GitHub builds it automatically without any Actions workflow.
Jekyll is a Ruby-based static site generator that turns Markdown files into HTML. GitHub Pages uses Jekyll by default when no Actions workflow is configured and the source is set to a branch.
A Minimal Jekyll Site
Push these two files to main with Pages enabled and GitHub builds the Jekyll site automatically.
Jekyll Limitations on GitHub Pages
GitHub Pages only supports a specific set of Jekyll plugins (the "github-pages" gem). If you need custom plugins, you must build locally or with GitHub Actions and deploy the output rather than the source.
Checking Deployment Status
In the Repository
Go to the Actions tab. Look for the workflow named "pages build and deployment" (for branch deploys) or your custom workflow name (for Actions deploys). Click a run to see the build logs.
Via gh CLI
Troubleshooting Common Issues
Site not updating after push:
- Check the Actions tab for a failed deployment workflow.
- For branch deploys, ensure the files are in the correct folder (root or
/docs). - Wait 1-2 minutes — propagation takes time.
Custom domain not working:
- Verify the CNAME record is set correctly (use
digor an online DNS lookup tool). - Ensure the
CNAMEfile in the repository contains the correct domain. - DNS changes can take up to 48 hours to propagate globally.
Jekyll build failing:
- Check the Pages deployment log in the Actions tab.
- Common causes: invalid YAML frontmatter, unsupported plugin, syntax error in a Liquid template.
Practical Exercises
Exercise 1 — Deploy a Personal Site
- Create a repository named
yourusername.github.io. - Create an
index.htmlandstyle.cssusing the example in this lesson as a starting point. - Enable GitHub Pages from the
mainbranch, root folder. - Verify your site is live at
https://yourusername.github.io. - Make a change to the HTML, push it, and verify the live site updates.
Exercise 2 — Project Page for a Repository
- Pick any existing repository you own.
- Create a
/docsfolder with anindex.htmlfile documenting the project. - Enable Pages from the
mainbranch,/docsfolder. - Verify the project site is live at
https://yourusername.github.io/reponame.
Exercise 3 — Deploy with GitHub Actions
- Create a repository with a simple build step (even just
echo "built" > dist/index.html). - Write a GitHub Actions workflow that runs the build and deploys using
actions/upload-pages-artifactandactions/deploy-pages. - Push to
mainand watch the workflow run in the Actions tab. - Verify the site is live.
Exercise 4 — Custom Domain (Optional)
If you own a domain:
- Add it as a custom domain in GitHub Pages settings.
- Configure the DNS records at your registrar.
- Wait for DNS propagation and verify the site loads from your domain.
- Enable HTTPS enforcement.