How to Structure Websites in GitHub- A Developer's Guide

Why GitHub Pages Structure Matters More Than You Think

Most developers treat their GitHub repository like a digital junk drawer. Code, docs, images, random config files — everything dumped into one folder. Then they wonder why their GitHub Pages site won't build.

The structure of your repository directly affects:

You can have perfect content and broken builds because of a single misplaced file. This guide fixes that.

GitHub Pages: User Sites vs Project Sites

GitHub gives you two types of free hosting:

User Sites

One per account. Your content lives in a repository named username.github.io. The source sits at the root.

URL structure: https://username.github.io

Project Sites

Unlimited per account. Any repository can generate a site via Settings → Pages.

URL structure: https://username.github.io/repository-name

You can also serve a project site from a /docs folder within the repository instead of the root. This keeps your source files separate from your published site.

The Root Directory Structure That Works

For a basic static site (HTML, CSS, JS), your repository should look like this:

username.github.io/
├── index.html
├── about.html
├── contact.html
├── css/
│   └── styles.css
├── js/
│   └── scripts.js
├── images/
│   └── logo.png
└── _config.yml  (if using Jekyll)

That's it. No subdirectories deeper than necessary. No random folders.

GitHub Pages serves files from the root by default. Every file you want published needs to be at the root or inside a folder directly under it.

Jekyll Structure: What GitHub Actually Expects

If you're using Jekyll (GitHub's default site generator), the structure changes. GitHub runs Jekyll in safe mode, which means it ignores certain files and folders.

Jekyll Root Layout

username.github.io/
├── _config.yml
├── _includes/
│   ├── header.html
│   └── footer.html
├── _layouts/
│   ├── default.html
│   └── page.html
├── _posts/
│   ├── 2024-01-15-welcome.md
│   └── 2024-02-20-update.md
├── _sass/
│   └── main.scss
├── assets/
│   ├── css/
│   ├── js/
│   └── images/
├── index.html
└── about.md

Files and Folders Jekyll Ignores

Jekyll automatically skips:

If your site isn't building, check if you accidentally put content inside a _ folder. Jekyll won't process it.

The /docs Folder Method

Some teams prefer keeping the published site separate from source code. Use the /docs method:

my-project/
├── src/
│   ├── _config.yml
│   ├── index.html
│   └── css/
├── docs/          ← GitHub Pages serves this
│   ├── index.html
│   └── css/
├── .gitignore
└── README.md

Then in your repository settings: Source → Deploy from a branch → /docs folder.

This works well when you have a build process that compiles files into /docs. Your source stays clean.

Common Mistakes That Break Builds

1. Wrong Config File Location

_config.yml must be at the root of your repository or the root of your /docs folder. GitHub won't find it in subdirectories.

2. Case-Sensitive Filenames

Linux servers are case-sensitive. Image.png and image.png are different files. If you reference image.png in your HTML but the file is named Image.png, the image won't load.

3. Broken Relative Links

When your site lives at username.github.io/repo, relative links from index.html work fine. But if you have nested pages, links break.

Use absolute paths for project sites:

<!-- Wrong for project sites -->
<a href="/about.html">About</a>

<!-- Correct for project sites -->
<a href="/repository-name/about.html">About</a>

4. Forgetting the index.html

GitHub Pages requires an index.html or index.md at the root. Without it, you'll get a 404.

Comparing Site Structures

Method Best For Pros Cons
Root Files Simple static sites No build process, fast setup No templating, manual updates
Jekyll Blogs, documentation Built-in templating, posts system Learning curve, Liquid syntax
/docs Folder Project demos, CI/CD workflows Clean source separation Extra build step required
External CI/CD Complex sites, multiple environments Full control, any generator More setup, potential costs

Getting Started: Set Up Your Repository

Step 1: Create the Repository

Go to GitHub → New Repository. Name it exactly yourusername.github.io for a user site, or any name for a project site.

Step 2: Choose Your Structure

For a basic site, create this minimum structure:

yourusername.github.io/
├── index.html
├── _config.yml
└── css/
    └── style.css

Step 3: Enable GitHub Pages

Repository Settings → Pages → Source → Deploy from a branch → Select main and / (root).

Step 4: Wait and Verify

GitHub takes 30-60 seconds to build. Refresh the Settings page to confirm your site is live. Check for the green banner: "Your site is published at https://..."

If the build fails, go to the Actions tab. GitHub logs every build error there with line numbers.

Asset Organization

Keep your assets predictable:

Don't scatter assets across multiple folders. It makes debugging broken links a nightmare.

For Jekyll sites, put processed assets in /assets (not starting with _). Jekyll copies everything without an underscore to the final build.

Branch Strategy

You can publish from:

Stick with main + root for personal sites. Use the docs method when you have source code in the same repository.

What to Exclude from Publishing

Add a .gitignore file to prevent unnecessary files from cluttering your site:

node_modules/
.DS_Store
*.log
.env
_dist/
.cache/

GitHub automatically ignores node_modules for Jekyll sites, but adding it to .gitignore keeps your repository clean.

Custom Domains and Structure

Adding a custom domain doesn't change your structure. GitHub creates a CNAME file at the root when you configure it.

Keep the CNAME file. If you delete it, your custom domain stops working.

Update your DNS to point to GitHub's servers. The structure stays the same whether you use a custom domain or not.