GitHub Pages
Web Hosting Platform
GitHub Pages
Overview
GitHub Pages is a static site hosting service that can be hosted directly from GitHub repositories. With Jekyll integration providing automatic Markdown to HTML conversion and blogging capabilities, it's widely used for open-source project documentation and portfolio sites. It maintains consistent demand through tight GitHub integration.
Details
Launched in 2008, GitHub Pages is one of GitHub's signature features beloved by many developers. Particularly popular for open-source project documentation, personal portfolio sites, and technical blogs. Through integration with Jekyll (Ruby-based static site generator), it automatically converts Markdown files to HTML and enables utilization of rich theme and plugin ecosystems. Starting in 2025, it transitioned to GitHub Actions-based build processes, enabling more flexible customization and use of newer Jekyll versions.
Advantages and Disadvantages
Advantages
- Completely Free: Unlimited usage for public repositories
- GitHub Integration: Unified repository management and hosting
- Jekyll Integration: Automatic HTML generation from Markdown
- Custom Domain Support: Configuration of custom domains
- HTTPS Support: Automatic SSL certificate issuance
- GitHub Actions: Advanced build process customization
- Rich Themes: Numerous beautiful Jekyll themes available
Disadvantages
- Static Sites Only: No server-side processing possible
- Build Limitations: 10GB monthly bandwidth limit
- Jekyll Dependency: GitHub Actions required for other SSGs
- Performance: May be slower compared to dedicated CDNs
- Feature Limitations: Constraints on advanced features and plugins
Reference Pages
Code Examples
Basic Setup and Project Configuration
# Repository creation with GitHub CLI
gh repo create my-website --public --clone
cd my-website
# Jekyll site initialization
jekyll new . --force
bundle install
# Enable GitHub Pages (Settings > Pages)
# Source: Deploy from a branch or GitHub Actions
# Initial commit
git add .
git commit -m "Initial Jekyll site"
git push origin main
# _config.yml - Jekyll basic configuration
title: My Awesome Website
description: A great site built with Jekyll and hosted on GitHub Pages
baseurl: "" # Repository name (e.g., "/my-website")
url: "https://username.github.io"
# GitHub Pages configuration
github_username: your-username
repository: your-username/my-website
# Jekyll configuration
markdown: kramdown
highlighter: rouge
theme: minima
# Plugin configuration
plugins:
- jekyll-feed
- jekyll-sitemap
- jekyll-seo-tag
- jekyll-redirect-from
# Excluded files
exclude:
- Gemfile
- Gemfile.lock
- node_modules
- vendor/bundle/
- vendor/cache/
- vendor/gems/
- vendor/ruby/
Static Site Deployment
# .github/workflows/jekyll.yml - Jekyll GitHub Actions
name: Build and deploy Jekyll site to GitHub Pages
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1'
bundler-cache: true
cache-version: 0
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Build with Jekyll
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
env:
JEKYLL_ENV: production
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./_site
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Framework Integration (Next.js, React, Vue)
# .github/workflows/nextjs.yml - Next.js GitHub Actions
name: Deploy Next.js site to Pages
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- name: Setup Pages
uses: actions/configure-pages@v4
with:
static_site_generator: next
- name: Restore cache
uses: actions/cache@v4
with:
path: |
.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}
- name: Install dependencies
run: npm ci
- name: Build with Next.js
run: npm run build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./out
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
// next.config.js - GitHub Pages support
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
trailingSlash: true,
images: {
unoptimized: true
},
basePath: process.env.NODE_ENV === 'production' ? '/repository-name' : '',
assetPrefix: process.env.NODE_ENV === 'production' ? '/repository-name/' : '',
};
module.exports = nextConfig;
Custom Domains and SSL
# Custom domain configuration
echo "example.com" > CNAME
git add CNAME
git commit -m "Add custom domain"
git push origin main
# DNS configuration (CNAME record)
# example.com -> username.github.io
# www.example.com -> username.github.io
# _config.yml - Custom domain configuration
url: "https://example.com"
baseurl: ""
# Force HTTPS
enforce_ssl: true
# Custom domain plugin
plugins:
- jekyll-redirect-from
# Redirect configuration
redirect_from:
- /old-page/
- /another-old-page/
<!-- 404.html - Custom 404 page -->
---
layout: default
permalink: /404.html
---
<div class="error-page">
<h1>404 - Page Not Found</h1>
<p>The page you're looking for doesn't exist.</p>
<a href="{{ site.baseurl }}/" class="btn">Go Home</a>
</div>
<script>
// Client-side routing for SPA
(function() {
var path = window.location.pathname;
var base = '{{ site.baseurl }}';
// Routing handling for GitHub Pages
if (path !== base + '/404.html') {
window.location.replace(base + '/#' + path);
}
})();
</script>
Serverless Functions and APIs
# .github/workflows/api-simulation.yml - Pseudo API creation
name: Generate API Data
on:
push:
branches: [ main ]
schedule:
- cron: '0 0 * * *' # Daily execution
jobs:
generate-data:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Generate API data
run: |
mkdir -p api
# Generate user data
cat > api/users.json << 'EOF'
{
"users": [
{
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"created_at": "${{ steps.date.outputs.date }}"
}
],
"total": 1,
"generated_at": "${{ steps.date.outputs.date }}"
}
EOF
# Generate statistics data
node -e "
const stats = {
page_views: Math.floor(Math.random() * 10000),
unique_visitors: Math.floor(Math.random() * 1000),
last_updated: new Date().toISOString()
};
require('fs').writeFileSync('api/stats.json', JSON.stringify(stats, null, 2));
"
- name: Commit and push
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add api/
git diff --staged --quiet || git commit -m "Update API data"
git push
// _includes/api-client.js - Static API client
class StaticAPI {
constructor(baseUrl) {
this.baseUrl = baseUrl || '';
}
async get(endpoint) {
try {
const response = await fetch(`${this.baseUrl}/api/${endpoint}.json`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
console.error('API Error:', error);
return null;
}
}
// Search functionality (static database)
async search(query, type = 'posts') {
const data = await this.get(type);
if (!data) return [];
const searchTerm = query.toLowerCase();
return data.filter(item =>
item.title.toLowerCase().includes(searchTerm) ||
item.content.toLowerCase().includes(searchTerm)
);
}
}
// Usage example
const api = new StaticAPI('{{ site.baseurl }}');
// Data fetching on page load
document.addEventListener('DOMContentLoaded', async () => {
const users = await api.get('users');
const stats = await api.get('stats');
// Display data
if (users) {
document.getElementById('user-count').textContent = users.total;
}
if (stats) {
document.getElementById('page-views').textContent = stats.page_views;
}
});
CI/CD and Production Optimization
# .github/workflows/optimization.yml - Optimization workflow
name: Build and Optimize
on:
push:
branches: [ main ]
jobs:
build-and-optimize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build Jekyll site
run: |
bundle install
bundle exec jekyll build
- name: Optimize images
run: |
npm install -g imagemin-cli imagemin-webp imagemin-mozjpeg imagemin-pngquant
imagemin "_site/**/*.{jpg,jpeg,png}" --out-dir="_site" --plugin=mozjpeg --plugin=pngquant
- name: Minify HTML/CSS/JS
run: |
npm install -g html-minifier clean-css-cli uglify-js
# HTML minification
find _site -name "*.html" -exec html-minifier --collapse-whitespace --remove-comments {} \;
# CSS minification
find _site -name "*.css" -exec cleancss -o {} {} \;
# JS minification
find _site -name "*.js" -exec uglifyjs {} -o {} \;
- name: Generate PWA files
run: |
cat > _site/manifest.json << 'EOF'
{
"name": "${{ github.repository }}",
"short_name": "Site",
"start_url": "{{ site.baseurl }}/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000"
}
EOF
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./_site
# Gemfile - Jekyll plugin configuration
source "https://rubygems.org"
gem "jekyll", "~> 4.3.0"
gem "github-pages", group: :jekyll_plugins
group :jekyll_plugins do
gem "jekyll-feed"
gem "jekyll-sitemap"
gem "jekyll-seo-tag"
gem "jekyll-redirect-from"
gem "jekyll-paginate"
gem "jekyll-gist"
gem "jekyll-github-metadata"
gem "jekyll-include-cache"
gem "jekyll-compress-images"
gem "jekyll-minifier"
end
# Performance monitoring
gem "jekyll-analytics"
# Development
group :development do
gem "webrick"
end
# Development and operations command collection
# Local development
bundle exec jekyll serve --livereload --port 4000
# Production build
JEKYLL_ENV=production bundle exec jekyll build
# Update dependencies
bundle update
# GitHub Pages compatibility check
github-pages health-check
# Site analysis
bundle exec jekyll doctor
# Preview (GitHub Pages environment)
act -W .github/workflows/pages.yml