Auto-Deploy a Portfolio Website

Build a CI/CD pipeline with GitHub Actions to auto-deploy a portfolio site.

Introduction

30 Second Summary

Imagine updating your website and having to manually upload files every single time. Professional developers skip that hassle by using automated pipelines that deploy code the moment it's ready.

In this project, you will build a personal portfolio website and set up a CI/CD pipeline using GitHub Actions that automatically deploys your site to the internet every time you push a code change.

What You'll Build

A portfolio website built with HTML and CSS, version-controlled with Git, and automatically deployed to GitHub Pages through a GitHub Actions workflow.

By the end of this project, you'll have:

  • A portfolio website built with HTML and CSS.
  • A GitHub repository with version-controlled source code.
  • A GitHub Actions workflow written in YAML that automatically deploys your site on every push.
  • Secret Mission: Add a "Projects" section with stylish hover-effect cards and trigger a fresh auto-deploy.

Are there any prerequisites?

You need a free GitHub account. If you don't have one yet, sign up at github.com before starting. This project is designed for macOS.

Set Up Your Mac for Development

Before you can build and deploy your portfolio website, your Mac needs a few developer tools. Right now, your machine does not have the software required to track code changes or push them to GitHub.

In this step, you will install three things: Git (the version control tool that tracks your code changes), Homebrew (a package manager that makes installing software easy), and the GitHub CLI (a tool that lets you interact with GitHub from your terminal).

In this step, get ready to:
  • Install Git via the Xcode Command Line Tools.
  • Install Homebrew and GitHub CLI.
  • Log in to GitHub from your terminal.
Open Terminal and install the Xcode Command Line Tools

The Xcode Command Line Tools are a set of developer utilities from Apple. They include Git, which you will use throughout this project to save and push your code.

  • Press Cmd+Space to open Spotlight search.
  • Type Terminal and press Enter to open it.

Terminal is the command-line app built into macOS. This is where you will run all your commands for the rest of the project.

  • Install the Xcode Command Line Tools by running this command:
xcode-select --install

What happens next?

A dialog window pops up asking if you want to install the developer tools. Click Install and agree to the license terms. The installation takes a few minutes.

If you see a message saying the tools are already installed, that is perfectly fine. Skip ahead to the verification step below.

  • Once the installation finishes, verify that Git is available by running:
git --version

✔️ I see a version number

You should see something like git version 2.x.x. The exact number does not matter. Git is installed and ready.

ⓧ Command not found

The Xcode Command Line Tools may not have installed correctly. Try these steps:

  • Run xcode-select --install again and make sure you click Install when the dialog appears.
  • Wait for the installation to fully complete before running git --version again.
  • If you still see an error, restart your terminal and try the version check one more time.
Install Homebrew and GitHub CLI

Homebrew is the standard package manager for macOS. Think of it as an app store for developer tools that runs entirely in Terminal. You will use it to install the GitHub CLI.

  • Install Homebrew by running this command:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

What to expect during installation

The installer may ask for your Mac password. Type it in and press Enter. You will not see any characters appear as you type. This is normal.

The installation takes a few minutes. When it finishes, look carefully at the output. On Apple Silicon Macs (M1, M2, M3, M4), the installer shows two commands under Next steps that you must run to add Homebrew to your PATH.

  • If you have an Apple Silicon Mac, copy and run the two commands shown by the installer. They typically look like this:
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

Copy the commands from your installer output

The exact commands in your terminal may differ slightly from the ones shown above. Always copy the commands directly from your installer output to be safe.

If your Mac has an Intel chip, Homebrew installs to a location that is already in your PATH. You can skip these PATH commands entirely.

  • Verify Homebrew is working by running:
brew --version

You should see a version number like Homebrew 4.x.x.

Seeing 'command not found: brew'?

This means Homebrew is not in your PATH. Make sure you ran the two PATH commands from the installer output. Then close and reopen Terminal before trying brew --version again.

Still stuck? Help me fix my Homebrew installation on macOS.

  • Install the GitHub CLI by running:
brew install gh
  • Verify the installation by running:
gh --version

You should see a version number in the output. The exact number does not matter.

Seeing an error from brew install?

Make sure brew --version works first. If Homebrew is not working, fix that before trying to install anything with it.

If Homebrew works but brew install gh fails, check your internet connection and try again. Help me troubleshoot my GitHub CLI installation.

Log in to GitHub from Terminal

GitHub no longer accepts passwords for pushing code over HTTPS. The GitHub CLI provides the easiest way to authenticate. Once you log in, every git push and git pull command works automatically.

  • Start the login process by running this command:
gh auth login

What does this command do?

This command starts an interactive login flow. It asks you several questions in the terminal, then opens your browser to complete authentication. Follow the prompts below exactly.

  • Select GitHub.com when asked which account to log in to.
  • Select HTTPS when asked for your preferred protocol.
  • Type Y and press Enter when asked to authenticate with your GitHub credentials.
  • Select Login with a web browser when asked how you would like to authenticate.

A one-time code appears in your terminal.

  • Press Enter to open your browser.
  • Paste the one-time code into the browser window that opens.
  • Click Authorize to grant the GitHub CLI access to your account.

Switch back to your terminal. You should see a confirmation message saying you are logged in.

  • Configure Git to use your GitHub login automatically by running:
gh auth setup-git

Why do I need this command?

This tells Git to use the GitHub CLI as its credential helper. Without it, Git would ask you for a username and password every time you push code. With it, every git push and git pull is seamless.

  • Verify everything is working by running:
gh auth status

You should see output confirming you are logged in to github.com as your GitHub username.

Not seeing a logged-in status?

Make sure you completed the browser authorization step. If you closed the browser tab before clicking Authorize, run gh auth login again and follow the prompts from the beginning.

Help me troubleshoot my GitHub CLI authentication.

Your Mac is now fully set up for development. Next up, you will create a GitHub repository and start building your portfolio website.

Create Your GitHub Repository

Your development environment is ready with Git, Homebrew, and GitHub CLI installed. Before you can build anything, you need a home for your project's code on GitHub.

In this step, you'll create a repository using the GitHub CLI and clone it to your Mac. This gives you a local folder to work in and a remote copy that GitHub Actions can deploy from later.

In this step, get ready to:
  • Create a public GitHub repository called my-portfolio.
  • Clone the repository to your Mac.
  • Open the project folder in VS Code.
Create a new repository using the GitHub CLI

A repository is a project folder that lives on GitHub and tracks every change you make to your files. You'll create one with a single terminal command.

  • Navigate to your home folder by running this command:
cd ~

What is ~ (tilde)?

The ~ character is a shortcut for your Mac's home folder. This is the default folder for your user account, typically at /Users/yourname.

  • Create your repository and clone it to your Mac by running this command:
gh repo create my-portfolio --public --clone --add-readme

What does this command do?

  • gh repo create my-portfolio creates a new repository called my-portfolio on your GitHub account.
  • --public makes the repository visible to everyone. GitHub Actions is free and unlimited for public repositories.
  • --clone downloads the repository to your Mac as a local folder so you can work on it.
  • --add-readme creates a README.md file so the repository is not empty.

You should see output confirming the repository was created on GitHub, followed by a Cloning into 'my-portfolio'... message.

Seeing an error?

  • If you see an authentication error, run gh auth login again and follow the prompts from Step 1.
  • If you see name already exists on this account, you already have a repository with that name. Delete it on GitHub.com first, or choose a different name.

Still stuck? Help me troubleshoot the gh repo create command.

Move into the project folder
  • Enter the my-portfolio folder by running this command:
cd my-portfolio
  • Confirm the repository files exist by running:
ls

You should see README.md in the output. This file was automatically created by the --add-readme flag.

Open the project in VS Code
  • Open the current folder in VS Code by running this command:
code .

✔️ VS Code opened

VS Code opens with the my-portfolio folder loaded. You should see README.md listed in the Explorer sidebar on the left.

ⓧ Command not found

The code command needs to be installed from inside VS Code first. Follow these steps to set it up.

  • Press Cmd+Space to open Spotlight search.
  • Type Visual Studio Code and press Enter to open it.
  • Press Cmd+Shift+P to open the Command Palette.
  • Type shell command in the search bar.
  • Select Shell Command: Install 'code' command in PATH.
  • Go back to your terminal and run code . again.

Why does your repo exist in two places?

Your my-portfolio repository now exists in two places: on GitHub.com (the remote copy) and on your Mac (the local copy). You'll make changes locally and push them to the remote copy.

Later, GitHub Actions will watch the remote copy and automatically deploy your site every time you push new changes.

Your repository is set up and open in VS Code. Next up, you'll build the actual portfolio website with HTML and CSS.

Build Your Portfolio Website

Your repository is created and your project is open in VS Code. Now it's time to build the actual website that your CI/CD pipeline will deploy.

You'll create two files: index.html for the page structure and style.css for the visual design. Together, they make a clean portfolio page you can show off to the world.

In this step, get ready to:
  • Create the HTML structure for your portfolio page.
  • Style the page with CSS for a clean, modern look.
  • Preview your website locally in the browser.
Create the HTML structure for your portfolio

Every website starts with an HTML file that defines the page's content and structure. Your index.html file is the main page visitors will see when they land on your site.

  • In VS Code, hover over the file explorer on the left sidebar and click the New File icon (it looks like a page with a small plus sign).
  • Type index.html as the file name and press Enter.
  • Make sure the file is created at the root of the project (directly inside my-portfolio), not inside any subfolder.
  • Copy the following code into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio</title>
    <!-- Link to the external stylesheet -->
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <!-- Page header with your name and tagline -->
    <header>
        <h1>Hi, I'm [[YOURNAME="Your Name"]]</h1>
        <p>Welcome to my portfolio site, deployed with GitHub Actions!</p>
    </header>
    <main>
        <!-- About Me section -->
        <section class="about">
            <h2>About Me</h2>
            <p>I'm learning DevOps and building my first CI/CD pipeline. This site is automatically deployed every time I push a change to GitHub.</p>
        </section>
        <!-- Skills list section -->
        <section class="skills">
            <h2>What I'm Learning</h2>
            <ul>
                <li>Git and GitHub</li>
                <li>GitHub Actions</li>
                <li>CI/CD Pipelines</li>
                <li>YAML Configuration</li>
            </ul>
        </section>
    </main>
    <!-- Footer -->
    <footer>
        <p>Deployed automatically with GitHub Actions</p>
    </footer>
</body>
</html>

What does this code do?

  • The <head> section sets up the page title and links to your CSS file for styling.
  • The <header> displays your name and a short tagline at the top of the page.
  • Two <section> elements organize your content into "About Me" and "What I'm Learning" blocks.
  • The <ul> list holds four skills that your CSS will turn into styled pill-shaped tags.
  • The <footer> adds a note at the bottom that your site is deployed with GitHub Actions.
  • Save index.html by pressing Cmd+S.
  • Confirm the file exists by running this command in the VS Code integrated terminal (press Ctrl+` to open it):
ls

You should see index.html and README.md listed in the output.

Don't see index.html in the output?

  • Make sure you created the file at the root of the my-portfolio folder, not inside a subfolder. Check the VS Code sidebar to confirm the file sits at the top level alongside README.md.
  • Double check that your terminal is inside the my-portfolio directory. Run pwd to check your current location.
  • Still stuck? Help me figure out why my index.html file isn't showing up when I run ls.

✔️ Awesome, I've got everything!

Great. Double check you've saved index.html before moving on.

ⓧ I'd like to double check the full code

Here is the full index.html file for comparison. Make sure your version matches this (with your own name replacing [Your Name]).

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>Hi, I'm [Your Name]</h1>
        <p>Welcome to my portfolio site, deployed with GitHub Actions!</p>
    </header>
    <main>
        <section class="about">
            <h2>About Me</h2>
            <p>I'm learning DevOps and building my first CI/CD pipeline. This site is automatically deployed every time I push a change to GitHub.</p>
        </section>
        <section class="skills">
            <h2>What I'm Learning</h2>
            <ul>
                <li>Git and GitHub</li>
                <li>GitHub Actions</li>
                <li>CI/CD Pipelines</li>
                <li>YAML Configuration</li>
            </ul>
        </section>
    </main>
    <footer>
        <p>Deployed automatically with GitHub Actions</p>
    </footer>
</body>
</html>
Style your portfolio with CSS

HTML defines the content, but CSS controls how it looks. Without a stylesheet, your page would appear as plain black text on a white background.

  • In VS Code, click the New File icon in the sidebar again.
  • Type style.css as the file name and press Enter.
  • Add the foundation and header styles by copying this code into style.css:
/* Reset default browser styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Center content with a readable width */
body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: #333;
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
}

/* Style the header with a blue theme */
header {
    text-align: center;
    padding: 3rem 0;
    border-bottom: 2px solid #0366d6;
}

header h1 {
    font-size: 2.5rem;
    color: #0366d6;
    margin-bottom: 0.5rem;
}

header p {
    font-size: 1.2rem;
    color: #586069;
}

What does this code do?

  • The * selector resets all elements so every browser starts from the same baseline.
  • The body styles center the page content and cap it at 800px wide for readability.
  • The header styles center the text, add padding, and give it a blue bottom border to make it stand out.
  • Save style.css.
  • You won't see a change yet because the page is not open in a browser. The next chunk adds the remaining content and footer styles.
  • Add the content area, skill tag, and footer styles below the code you just pasted in style.css:
/* Add spacing around the main content */
main {
    padding: 2rem 0;
}

section {
    margin-bottom: 2rem;
}

/* Style section headings with an underline */
h2 {
    font-size: 1.5rem;
    color: #24292e;
    margin-bottom: 1rem;
    border-bottom: 1px solid #e1e4e8;
    padding-bottom: 0.5rem;
}

/* Display skills as pill-shaped tags */
ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

li {
    background: #f1f8ff;
    color: #0366d6;
    padding: 0.5rem 1rem;
    border-radius: 20px;
    font-size: 0.9rem;
    border: 1px solid #c8e1ff;
}

/* Style the footer */
footer {
    text-align: center;
    padding: 2rem 0;
    border-top: 1px solid #e1e4e8;
    color: #586069;
    font-size: 0.9rem;
}

What does this code do?

  • list-style: none removes the default bullet points from the skills list.
  • display: flex and flex-wrap: wrap arrange the skill items in a horizontal row that wraps to the next line if the screen is narrow.
  • border-radius: 20px on each li gives the skill items a rounded pill shape with a light blue background.
  • The footer gets a subtle top border to separate it from the content above.
  • Save style.css.
  • You'll see the full styled site in the next substep when you preview it in the browser.

✔️ Awesome, I've got everything!

Great. Double check you've saved style.css before moving on.

ⓧ I'd like to double check the full code

Here is the full style.css file for comparison.

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: #333;
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
}

header {
    text-align: center;
    padding: 3rem 0;
    border-bottom: 2px solid #0366d6;
}

header h1 {
    font-size: 2.5rem;
    color: #0366d6;
    margin-bottom: 0.5rem;
}

header p {
    font-size: 1.2rem;
    color: #586069;
}

main {
    padding: 2rem 0;
}

section {
    margin-bottom: 2rem;
}

h2 {
    font-size: 1.5rem;
    color: #24292e;
    margin-bottom: 1rem;
    border-bottom: 1px solid #e1e4e8;
    padding-bottom: 0.5rem;
}

ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

li {
    background: #f1f8ff;
    color: #0366d6;
    padding: 0.5rem 1rem;
    border-radius: 20px;
    font-size: 0.9rem;
    border: 1px solid #c8e1ff;
}

footer {
    text-align: center;
    padding: 2rem 0;
    border-top: 1px solid #e1e4e8;
    color: #586069;
    font-size: 0.9rem;
}
Preview your website locally

Before you deploy anything, it is a good idea to preview the site on your own machine first. This catches any issues before the whole world sees them.

  • Open your website in a browser by running this command in the VS Code integrated terminal:
open index.html

Your default browser opens with your portfolio page. You should see your name in large blue text at the top, centered on the page with a blue bottom border.

Below that, you should see an "About Me" section with a paragraph of text, and a "What I'm Learning" section with four skill tags displayed as rounded blue pills.

Page looks like plain unstyled text?

  • Check that style.css is in the same folder as index.html. Both files must sit at the root of my-portfolio.
  • Verify the <link> tag in your index.html says href="style.css" exactly. A typo like styles.css (with an extra 's') will break the link.
  • Make sure you saved both files before opening the browser.
  • Still stuck? Help me figure out why my CSS styles are not showing up in the browser.

Seeing a blank page?

  • Open index.html in VS Code and make sure the file is not empty. It should start with <!DOCTYPE html>.
  • If you accidentally opened a different file or the wrong folder, run pwd in the terminal to confirm you are inside ~/my-portfolio.
  • Help me troubleshoot why my index.html is showing a blank page.

Your portfolio is looking good locally. Next up, you'll save your code with Git and push it to GitHub so your files are stored safely in the cloud.

Save and Push Your Code to GitHub

Your portfolio website is built and looking sharp in the browser. Now it's time to save your work and send it to GitHub.

Git uses a three-step flow to save and share your code: stage, commit, push. Each step gives you control over exactly what changes get recorded and when they leave your computer.

In this step, get ready to:
  • Stage your files so Git knows which changes to include.
  • Create a commit to save a snapshot of your project.
  • Push your code to GitHub so it lives in the cloud.
Stage your files
  • In the VS Code integrated terminal (press Ctrl+` to open it), stage all your new files by running this command:
git add .

What does staging mean?

Git doesn't automatically include every file in your next save point. Staging is how you tell Git "I want these specific files in my next commit."

The . at the end of git add . means "everything in this folder." It stages all new and changed files at once.

  • Verify your files are staged by running:
git status

You should see index.html and style.css listed in green under "Changes to be committed."

Not seeing your files in green?

  • Make sure your terminal is inside the my-portfolio folder. Run pwd to check. If you're somewhere else, run cd ~/my-portfolio to get back.
  • If your files show as "Untracked files" in red, you haven't staged them yet. Run git add . again.
  • Why aren't my files showing as staged in Git?
Create a commit

A commit is a snapshot of your project at a specific moment in time. Every commit gets a message that describes what changed.

  • Create a commit with a descriptive message by running this command:
git commit -m "Add portfolio website"

You should see output showing 2 files changed with several insertions.

What does the -m flag do?

The -m flag lets you write your commit message inline. Without it, Git opens a text editor for you to type the message. Keeping the message in the command is faster for quick commits.

Seeing 'nothing to commit'?

  • This means your files were not staged. Run git add . first, then run the commit command again.
  • If you see a message about setting your identity, Git needs your name and email. Follow the instructions it shows to set them, then try the commit again.
  • Why is my git commit failing?
Push your code to GitHub

Your commit is saved locally on your Mac. Pushing sends it to your GitHub repository so it's stored in the cloud and visible to anyone with the link.

  • Send your commit to GitHub by running this command:
git push
  • Open your browser and visit your repository on GitHub.com. The URL follows this pattern:
https://github.com/[[GITHUB_USERNAME="your GitHub username"]]/my-portfolio
  • Confirm you can see index.html and style.css listed alongside your README.md in the repository file list.

Push failed or files not showing?

  • If you see an authentication error, run gh auth status to check your login. If you're not logged in, run gh auth login again and then try git push.
  • If you see "Everything up-to-date," your commit may not have gone through. Run git status to check for uncommitted changes, then stage and commit them.
  • If your files are on GitHub but look different than expected, make sure you saved both files in VS Code before running git add ..
  • Why is my git push failing?

Your code is safely on GitHub. Next, you'll create a GitHub Actions workflow that automatically deploys your site every time you push a change.

Create Your GitHub Actions Workflow

Your portfolio code is on GitHub, and you've proven you can push changes with Git. Right now, if you wanted that code live on the internet, you'd have to manually upload it to a server every single time you make a change.

That's where CI/CD comes in. You'll write a GitHub Actions workflow file that tells GitHub to automatically deploy your site every time you push code. One file, and you never have to manually deploy again.

In this step, get ready to:
  • Create the .github/workflows/ directory that GitHub Actions requires.
  • Write a YAML workflow file that defines your deployment pipeline.
  • Push the workflow to GitHub and trigger your first automated run.
Create the workflow directory and file

GitHub Actions looks for workflow files in a specific folder inside your repository: .github/workflows/. If this folder doesn't exist, GitHub Actions won't know about any workflows you create.

  • Create the required folder structure by running this command in your VS Code integrated terminal:
mkdir -p .github/workflows
  • Confirm the folder was created by running:
ls .github

You should see workflows in the output.

What does -p do?

The -p flag tells mkdir to create the entire chain of folders at once. Without it, you'd get an error because the .github parent folder doesn't exist yet.

Now you need to create the workflow file itself inside that folder.

  • In the VS Code Explorer sidebar on the left, click the arrow next to .github to expand it.
  • Click the arrow next to workflows to expand it.
  • Hover over the workflows folder name and click the New File icon (it looks like a page with a plus sign).
  • Type deploy.yml and press Enter.

An empty deploy.yml file opens in the editor. This is where your deployment workflow will live.

Don't see the .github folder?

Folders that start with a dot (like .github) are hidden by default on macOS. VS Code should still show them in the Explorer sidebar. If you don't see it, make sure you ran the mkdir command from inside your my-portfolio folder.

help me find the .github folder in my VS Code Explorer

Write the deployment workflow

A GitHub Actions workflow is written in YAML, a configuration language that uses indentation to show structure. Each line is a key-value pair, and spacing matters.

  • Copy the following code into your empty deploy.yml file:
# Name displayed in the Actions tab on GitHub
name: Deploy to GitHub Pages

# Run this workflow every time code is pushed to the main branch
on:
  push:
    branches:
      - main

# Grant the workflow permission to read code and deploy to Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Define the deployment job
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      # Download your repository code onto the cloud server
      - name: Checkout code
        uses: actions/checkout@v6

      # Prepare GitHub Pages for deployment
      - name: Setup Pages
        uses: actions/configure-pages@v5

      # Package your site files into a deployable artifact
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v4
        with:
          path: '.'

      # Deploy the artifact to GitHub Pages
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

What does this workflow do?

This file has four key sections:

  • name gives your workflow a human-readable label that appears in the Actions tab on GitHub.
  • on: push with branches: [main] tells GitHub to run this workflow every time you push code to the main branch.
  • permissions grants the workflow access to read your code, write to GitHub Pages, and create a secure deployment token.
  • jobs defines a single job called deploy that runs on a cloud server (ubuntu-latest). It checks out your code, configures Pages, uploads your site files, and deploys them.

What is YAML?

YAML is a human-readable file format used for configuration. It uses indentation (spaces, not tabs) to show structure. Each line is typically a key-value pair like name: Deploy to GitHub Pages.

Indentation is critical in YAML. If a line is indented incorrectly, the workflow will fail to parse. Make sure your file uses spaces (not tabs) and that the indentation matches exactly.

  • Save deploy.yml by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • Verify the file appears at the correct path in the Explorer sidebar: .github > workflows > deploy.yml.

Seeing red squiggly lines in your YAML?

YAML is very sensitive to indentation. Make sure every line uses spaces (not tabs) and matches the indentation shown above exactly. Even one extra or missing space can break the file.

Also check that you pasted the code into deploy.yml (not deploy.yaml or another file). Both extensions work, but the file name must match exactly.

help me fix YAML indentation errors in my deploy.yml file

✔️ Awesome, I've got everything!

Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete deploy.yml file. Make sure your file matches this exactly:

name: Deploy to GitHub Pages

on:
  push:
    branches:
      - main

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Pages
        uses: actions/configure-pages@v5

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v4
        with:
          path: '.'

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
Push the workflow to GitHub

Your workflow file only lives on your Mac right now. To activate it, you need to push it to GitHub. The moment GitHub receives a workflow file in .github/workflows/, it starts watching for the trigger you defined.

  • Stage, commit, and push your workflow file by running these commands:
git add .
git commit -m "Add GitHub Actions deploy workflow"
git push

What do these commands do?

  • git add . stages all new and changed files (your deploy.yml and the new folders).
  • git commit -m "..." saves a snapshot of your project with a descriptive message.
  • git push sends your commit to GitHub. Because your workflow triggers on: push to main, this push immediately triggers your first workflow run.
  • Open your browser and go to your repository on GitHub.com.
  • Click the Actions tab at the top of the repository page.

You should see a workflow run named Add GitHub Actions deploy workflow (matching your commit message). It might show a yellow dot (in progress) or a red X (failed).

A failure at this point is completely normal. You haven't enabled GitHub Pages as the deployment target yet. You'll do that in the next step.

Don't see any workflow runs?

Make sure your deploy.yml file is inside .github/workflows/ and not in the root of your project. GitHub only detects workflow files in that exact directory.

Also check that git push completed successfully in your terminal. If you see an error, make sure you are logged in by running gh auth status.

help me figure out why my GitHub Actions workflow is not appearing

Your CI/CD pipeline is now on GitHub and ready to deploy. Next up, you'll activate GitHub Pages so your workflow has somewhere to send your site.

Activate GitHub Pages and See Your Live Site

Your code and workflow file are on GitHub. The workflow already triggered its first run when you pushed it.

GitHub Pages does not automatically use your workflow for deployment. In this step, you will configure that setting and see your portfolio go live.

In this step, get ready to:
  • Enable GitHub Pages with GitHub Actions as the deployment source.
  • Confirm the workflow completes with a green checkmark.
  • Visit your live portfolio website.
Enable GitHub Pages in your repository settings

Your workflow knows how to deploy, but GitHub Pages needs to be told to use it. Without this setting, GitHub ignores the deploy step entirely.

  • Open your browser and go to your my-portfolio repository on GitHub.com.
  • Click the Settings tab in the top navigation bar of your repository.
  • In the left sidebar, scroll down to the Code and automation section.
  • Click Pages.
  • Under Build and deployment, find the Source dropdown.
  • Select GitHub Actions from the dropdown.

The page should now show GitHub Actions selected as the source under Build and deployment.

What does this setting do?

GitHub Pages can deploy files directly from a branch, or it can use a workflow. By selecting GitHub Actions, you are telling GitHub to run your deploy.yml workflow every time it needs to update the site.

Watch your workflow run

When you pushed your workflow file in the previous step, it triggered a run automatically. That run may have failed because GitHub Pages was not configured yet.

  • Click the Actions tab in the top navigation bar of your repository.

You should see the Deploy to GitHub Pages workflow listed with at least one run.

✔️ I see a green checkmark

Your workflow completed successfully. Skip ahead to the next substep to visit your live site.

ⓧ I see a red X or failed run

The first run likely failed because GitHub Pages was not enabled yet. Now that you have configured it, you can re-run the workflow.

  • Click on the failed workflow run to open it.
  • Click the Re-run all jobs button in the top right corner.
  • Click Re-run jobs to confirm.

Wait for the workflow to complete. Green checkmarks appear next to each step as it finishes.

Workflow still failing after re-run?

  • Make sure you selected GitHub Actions as the source in Settings > Pages. The workflow cannot deploy without this setting.
  • Double check that your deploy.yml file is inside the .github/workflows/ folder. GitHub Actions only detects workflows in that exact path.
  • Make sure your repository is set to Public. GitHub Pages is free for public repositories only on the free plan.
  • Help me debug my GitHub Actions deployment
Visit your live website
  • Click the Settings tab in your repository.
  • Click Pages in the left sidebar under Code and automation.

You should see a banner saying "Your site is live at" followed by a URL. The URL follows the pattern https://yourusername.github.io/my-portfolio.

  • Click the URL to open your live portfolio website in a new tab.

Your portfolio is now live on the internet. It was deployed automatically by your CI/CD pipeline.

Seeing a 404 page?

  • It can take 1-2 minutes for your site to become available after the workflow completes. Wait a moment and refresh the page.
  • Make sure your repository has an index.html file in the root folder (not inside any subfolder). GitHub Pages looks for this file as the entry point.
  • Confirm the workflow shows a green checkmark on the Actions tab. If the workflow failed, your site was not deployed.
  • Help me fix my GitHub Pages 404 error

Your portfolio is live on the internet. Next up, you will make a change and watch the pipeline auto-deploy it with zero manual steps.

Update Your Site and Watch Auto-Deploy

Your portfolio website is live on the internet. Anyone with your URL can visit it right now.

The real power of a CI/CD pipeline shows up when you make changes. In this step, you will edit your site, push the update, and watch your pipeline handle the deployment automatically.

In this step, get ready to:
  • Make a text change to your portfolio website.
  • Push the update to GitHub using Git.
  • Watch your GitHub Actions workflow auto-deploy the change to your live site.
Make a change to your website

Your CI/CD pipeline is watching the main branch for changes. The moment you push new code, it springs into action. Let's give it something to deploy.

  • In VS Code, open index.html.
  • Scroll down to the "What I'm Learning" section and find the skills list. It looks like this:
            <ul>
                <li>Git and GitHub</li>
                <li>GitHub Actions</li>
                <li>CI/CD Pipelines</li>
                <li>YAML Configuration</li>
            </ul>
  • Add a new <li> element inside the <ul>, right after the last list item. You can write anything you like. For example, you could add <li>HTML & CSS</li> on a new line above the closing </ul> tag.
  • Save the file with Cmd+S.

What change should I make?

Any text change works for this exercise. The goal is to see the CI/CD loop in action, not to build a specific feature.

Adding a list item is the simplest option because it is easy to spot on the live page after deploy.

Push the update to GitHub

Your change only exists on your Mac right now. Git does not know about it yet. You need to stage, commit, and push. This is the same three-step flow you used in the previous step.

  • Stage, commit, and push your change by running these commands in the VS Code integrated terminal:
git add .
git commit -m "Update portfolio content"
git push

Quick recap on these commands

  • git add . stages all changed files so Git knows to include them in the next commit.
  • git commit -m "..." saves a snapshot of your project with a description of what changed.
  • git push sends the snapshot to GitHub. This is the trigger that kicks off your workflow.
  • After running git push, you should see output ending with a line like main -> main, confirming your code reached GitHub.

Push failed?

  • Make sure you are inside the my-portfolio folder. Run pwd to check your current directory.
  • If you see "Permission denied", run gh auth status to confirm you are still logged into GitHub.
  • Why is my git push failing?
Watch the pipeline auto-deploy

Your push just triggered the GitHub Actions workflow. Every push to main kicks off a fresh deploy automatically. No buttons to click, no servers to configure.

  • Open your repository on GitHub.com.
  • Click the Actions tab at the top of the repository page.
  • You should see a new workflow run called Update portfolio content (matching your commit message). Click on it to watch the steps execute in real time.
  • Wait for a green checkmark to appear next to every step in the workflow.

Once you see the green checkmark, your updated site is live.

  • Open your portfolio URL in a new browser tab. The URL follows the pattern https://yourusername.github.io/my-portfolio.
  • If the page was already open, refresh it.

You should see your new skill item (or whatever change you made) on the live page.

What is the CI/CD loop?

You just experienced the full CI/CD loop: make a code change, push it, and automation handles building and deploying.

This is the same pattern used by professional engineering teams worldwide. The only difference is scale. Instead of one HTML file, teams push hundreds of changes a day across dozens of services. The loop stays the same.

Don't see your changes on the live site?

  • The workflow may take 1-2 minutes to complete. Check the Actions tab for a green checkmark before refreshing your site.
  • Try a hard refresh with Cmd+Shift+R to clear your browser cache.
  • If the workflow run shows a red X, click on it to see the error details. The most common cause is a typo in the deploy.yml file.
  • My GitHub Pages site is not showing my latest changes. How do I debug this?

Secret mission

Add a Projects Section with Hover Cards

Your portfolio is live and auto-deploying. Time to level it up. Add a Projects section with stylish hover-effect cards, then push your changes and watch the CI/CD pipeline deploy them automatically.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on free services, so there are no ongoing costs.

Resources you used:

  • GitHub repository (my-portfolio).
  • GitHub Pages site (your live website URL).
  • GitHub Actions workflow (.github/workflows/deploy.yml).
  • Local project files (index.html, style.css).
  • Homebrew, GitHub CLI (gh), and Xcode Command Line Tools (installed on your Mac).

Keep everything running

No action needed. Choose this if you are still actively building your portfolio or plan to keep pushing updates.

  • Your GitHub Pages site stays live and free for public repositories.
  • Your GitHub Actions workflow continues to auto-deploy on every push at no cost.
  • Homebrew, GitHub CLI, and Xcode Command Line Tools remain useful for future projects.

Pause - I'll come back to this later

Disable your live site and workflow while keeping your code and repository intact. You can re-enable everything when you are ready to continue.

  • Go to your repository on GitHub.com.
  • Click Settings, then click Pages in the left sidebar.
  • Under Build and deployment, change the Source dropdown back to None to take your site offline.
  • Your repository, code, and workflow file all stay on GitHub. When you are ready to resume, set the source back to GitHub Actions and push a change to redeploy.

Delete - I don't want to use this again

Remove all project resources and start fresh. This permanently deletes your repository and live site.

  • Go to your repository on GitHub.com.
  • Click Settings.
  • Scroll to the bottom of the page and click Delete this repository under the Danger Zone section.
  • Follow the confirmation prompts to delete the repository. This also removes your GitHub Pages site.
  • Delete the local project folder by running this command in Terminal:
rm -rf ~/my-portfolio

What about Homebrew and GitHub CLI?

Keep Homebrew and GitHub CLI installed. They are general-purpose developer tools you will use in future projects.

Mission accomplished

That's a Wrap!

You just built your first CI/CD pipeline. You now have a live portfolio website that redeploys itself every time you push a code change to GitHub. That is the core DevOps loop in action.

Here's what you learned:

  • Built a portfolio website with HTML and CSS and deployed it live to GitHub Pages.
  • Wrote a GitHub Actions workflow in YAML that automatically deploys your site on every push to main.
  • Experienced the full CI/CD loop: write code, push to GitHub, and watch automation handle the rest.
  • Secret Mission: Added a Projects section with stylish hover-effect cards and triggered a fresh auto-deploy.

Ready to quiz yourself?