Skip to content
Build a Portfolio Website with Hugo (Step by Step)

Build a Portfolio Website with Hugo (Step by Step)

DodaTech Updated Jun 19, 2026 9 min read

Build a personal portfolio website with Hugo static site generator — choose a theme, configure about/projects/skills/contact sections, deploy to Netlify for free, and connect a custom domain.

What You’ll Build

You’ll build a personal portfolio site at yourname.netlify.app showcasing your projects, skills, and experience — without writing any backend code. Hugo generates static HTML files that load instantly, rank well on search engines, and cost nothing to host. This same approach powers DodaTech’s own documentation sites and Doda Browser’s landing page.

Why Hugo for a Portfolio?

Hugo is the world’s fastest static site generator — it builds thousands of pages in milliseconds. Unlike WordPress (slow, hackable) or React SPAs (poor SEO without SSR), Hugo produces plain HTML and CSS. It’s free, requires no database, and deploys to Netlify in one click. For a developer portfolio, it strikes the perfect balance between customization and simplicity.

Prerequisites

  • Git installed and basic familiarity
  • A GitHub account (free)
  • Basic HTML/Markdown knowledge
  • The desire to have a live portfolio by the end of this tutorial

Step 1: Install Hugo

# macOS
brew install hugo

# Linux (Ubuntu/Debian)
sudo apt install hugo
# Or get the latest from GitHub
wget https://github.com/gohugoio/hugo/releases/download/v0.127.0/hugo_extended_0.127.0_linux-amd64.deb
sudo dpkg -i hugo_extended_0.127.0_linux-amd64.deb

# Windows (chocolatey)
choco install hugo-extended -y

# Verify
hugo version
# Expected: hugo v0.127.0+extended ...

The “extended” version is required for Sass/SCSS support, which many themes use.

Step 2: Create the Site

hugo new site portfolio
cd portfolio

This creates:

portfolio/
├── archetypes/     # Content templates
├── assets/         # SCSS, JS, images
├── content/        # Your pages and blog posts
├── data/           # YAML/JSON data files
├── layouts/        # Override theme templates
├── static/         # Static files (CV PDF, favicon)
├── themes/         # Downloaded themes
├── hugo.toml       # Main configuration
└── public/         # Built output (gitignored)

Step 3: Choose and Install a Theme

We’ll use the Hugo Profile theme — a clean, modern portfolio theme:

cd themes
git init  # Required: the site is a Hugo module
# Option A: Git submodule
git submodule add https://github.com/gurusabarish/hugo-profile.git

# Option B: Download and extract manually
# curl -L https://github.com/gurusabarish/hugo-profile/archive/refs/heads/master.zip -o theme.zip
# unzip theme.zip && mv hugo-profile-master hugo-profile && rm theme.zip

cd ..

Configure the theme in hugo.toml:

baseURL = "https://yourname.netlify.app"
languageCode = "en-us"
title = "Your Name | Developer Portfolio"
theme = "hugo-profile"
publishDir = "public"

[params]
  titleEmoji = "👋"
  subtitle = "Full-Stack Developer"
  description = "I build web applications and developer tools. This is my portfolio."
  keywords = "developer, portfolio, full-stack, web development"
  author = "Your Name"
  email = "your@email.com"
  avatar = "images/avatar.jpg"
  enableDarkMode = true

  # Social links
  [[params.social]]
    name = "GitHub"
    url = "https://github.com/yourusername"
    icon = "github"
  [[params.social]]
    name = "LinkedIn"
    url = "https://linkedin.com/in/yourusername"
    icon = "linkedin"
  [[params.social]]
    name = "Twitter"
    url = "https://twitter.com/yourusername"
    icon = "twitter"

[menu]
  [[menu.main]]
    identifier = "about"
    name = "About"
    url = "/"
    weight = 1
  [[menu.main]]
    identifier = "projects"
    name = "Projects"
    url = "/projects"
    weight = 2
  [[menu.main]]
    identifier = "blog"
    name = "Blog"
    url = "/blog"
    weight = 3
  [[menu.main]]
    identifier = "contact"
    name = "Contact"
    url = "/contact"
    weight = 4

Step 4: Add Your Content

Homepage / About Section

<!-- content/_index.md -->
---
title: "Home"
---
## About Me

I'm a full-stack developer with 5 years of experience building web applications,
APIs, and developer tools. I specialize in Python, JavaScript, and cloud infrastructure.

**What I do:**
- Build scalable REST APIs and microservices
- Design responsive web interfaces
- Automate workflows with CI/CD pipelines
- Contribute to open-source projects

When I'm not coding, you'll find me hiking in the mountains or experimenting with
home automation projects.

[Download CV →](/cv.pdf)

Projects Section

<!-- content/projects/_index.md -->
---
title: "Projects"
---

Create individual project pages:

<!-- content/projects/chat-app.md -->
---
title: "Real-Time Chat App"
description: "WebSocket-based chat application"
date: 2026-05-15
tags: ["Python", "FastAPI", "WebSocket", "JavaScript"]
demoURL: "https://chat-app-demo.netlify.app"
repoURL: "https://github.com/yourusername/chat-app"
weight: 1
featured: true
---

A real-time chat application built with FastAPI WebSockets. Supports multiple
rooms, join/leave notifications, and message broadcasting. Handles 100+
concurrent connections with <50ms latency.

**Features:**
- Room-based messaging
- Live user presence
- Typing indicators
- Message history
<!-- content/projects/todo-app.md -->
---
title: "Todo App"
description: "Full-stack todo application"
date: 2026-04-01
tags: ["React", "Node.js", "SQLite", "Express"]
demoURL: "https://todo-app-demo.netlify.app"
repoURL: "https://github.com/yourusername/todo-app"
weight: 2
featured: false
---

A full-stack todo application with React frontend and Express backend.
Supports CRUD operations, filtering, and persistent storage with SQLite.

Blog Section

<!-- content/blog/_index.md -->
---
title: "Blog"
---
<!-- content/blog/first-post.md -->
---
title: "Why I Switched from WordPress to Hugo"
date: 2026-06-01
description: "My experience moving from a dynamic CMS to a static site generator."
tags: ["hugo", "wordpress", "static-site"]
---

Static site generators like Hugo offer speed, security, and simplicity
that WordPress can't match — especially for a developer portfolio...




[Continue reading...]

Contact Page

<!-- content/contact.md -->
---
title: "Contact"
---

## Get In Touch

I'm always open to new opportunities, collaborations, or just a chat.

- **Email:** your@email.com
- **GitHub:** [github.com/yourusername](https://github.com/yourusername)
- **LinkedIn:** [linkedin.com/in/yourusername](https://linkedin.com/in/yourusername)

Or use the form below:

Step 5: Add Visual Assets

mkdir -p static/images
# Add your profile photo
cp ~/Desktop/your-photo.jpg static/images/avatar.jpg
# Add a favicon (use a 32×32 PNG or ICO)
# Add your CV/resume PDF
cp ~/Desktop/cv.pdf static/cv.pdf

For the avatar, use a professional headshot or clean profile image. Square format (500×500px or larger) works best. The favicon can be generated at favicon.io using your initials.

Step 6: Build and Preview Locally

hugo server -D

Open http://localhost:1313. You’ll see your portfolio with the theme applied. The -D flag includes draft content. Make changes to content files — Hugo reloads instantly.

Expected output:

Web Server is available at http://localhost:1313/
Press Ctrl+C to stop

Your site should show:

  • Hero section with your photo, name, and tagline
  • About section with your bio
  • Projects grid with cards for chat-app and todo-app
  • Blog section with your first post
  • Contact section with your info

Step 7: Deploy to Netlify

# Initialize git
git init
git add .
git commit -m "Initial portfolio site"

# Create a repo on GitHub, then:
git remote add origin https://github.com/yourusername/portfolio.git
git branch -M main
git push -u origin main

Now deploy to Netlify:

  1. Go to netlify.com and sign in with GitHub
  2. Click Add new siteImport an existing project
  3. Select your portfolio repository
  4. Build settings will auto-detect Hugo (set hugo as build command, public as publish directory)
  5. Click Deploy site

Wait 1-2 minutes for the first build. Your site is live at random-name.netlify.app.

Step 8: Custom Domain (Optional)

  1. In Netlify, go to Site settingsDomain management
  2. Click Add custom domain → enter yourname.com
  3. Update your domain registrar’s DNS:
    • Point yourname.com to Netlify’s load balancer IP (find it in Netlify docs)
    • Or add a CNAME record for www.yourname.com pointing to your-site.netlify.app
  4. Wait for DNS propagation (5 minutes to 48 hours)
  5. Netlify automatically provisions an SSL certificate via Let’s Encrypt

Architecture


flowchart LR
    A[Write Markdown content] --> B[Hugo builds site]
    B --> C[Static HTML/CSS/JS]
    C --> D[git push to GitHub]
    D --> E[Netlify detects push]
    E --> F[Netlify runs hugo build]
    F --> G[Netlify deploys to CDN]
    G --> H[Visitor requests site]
    H --> I[CDN serves from edge]
    I --> J[Global low-latency delivery]

Common Errors

1. Hugo says “theme not found” The theme directory must be named exactly as specified in hugo.toml. If you downloaded hugo-profile-master, rename it to hugo-profile. Also ensure the theme is in themes/hugo-profile/ with a theme.toml file at the root.

2. Images not showing in the built site All images must go in static/ or assets/. Files in static/images/ are served at /images/filename.jpg. In markdown, reference them as /images/filename.jpg (not static/images/...). Images in assets/ can be processed by Hugo’s image pipeline (resize, crop, compress).

3. Netlify build fails with “Command not found: hugo” Netlify needs to know which Hugo version to use. Add a netlify.toml file:

[build]
  command = "hugo"
  publish = "public"

[context.production.environment]
  HUGO_VERSION = "0.127.0"

4. Custom domain shows “Site Not Found” DNS propagation can take hours. Use dig yourname.com to verify the DNS record points to Netlify. Check that the domain is spelled correctly in Netlify settings. Netlify’s SSL certificate provisioning can take up to 15 minutes after DNS resolves.

Practice Questions

1. Why is Hugo faster than WordPress? WordPress builds pages dynamically on every request — it queries a database, runs PHP, and renders HTML. Hugo builds everything once during hugo command. The output is plain HTML files that web servers serve directly without any processing. A Hugo site loads in milliseconds; WordPress often takes 500-2000ms.

2. What’s the difference between hugo server and hugo server -D? hugo server runs the development server but excludes draft pages (those with draft: true in front matter). -D includes drafts. Always use -D during development, then remove it when previewing the final site.

3. How do I update the theme without losing my changes? If you used git submodule add, run git submodule update --remote themes/hugo-profile to pull the latest theme version. If you modified theme files directly, your changes will conflict. Better approach: override theme templates in your site’s layouts/ directory — Hugo checks your layouts/ first, then falls back to the theme.

4. Challenge: Add a dark mode toggle Most Hugo themes (including Hugo Profile) have built-in dark mode. If not, add a JavaScript toggle that switches a data-theme attribute on <html>. Store the preference in localStorage. Style both modes using CSS custom properties: --bg: white; --text: black vs --bg: #1a1a2e; --text: #eee.

5. Challenge: Add a projects filter Create filter buttons (All, Python, JavaScript, DevOps) above your projects list. Use JavaScript to show/hide project cards based on their tags. Each project’s tags front matter becomes a CSS class on the card. This is pure frontend — no Hugo rebuild needed.

FAQ

Can I use a different theme?
Yes. Browse themes.gohugo.io and pick one you like. Common developer portfolio themes: Hugo Profile, Academic, Hello Friend, Mainroad, LoveIt. Each has different configuration sections — read the theme’s README for setup instructions.
How do I add analytics?
Netlify offers built-in analytics (paid) or use Google Analytics 4. Add the tracking code to layouts/partials/head.html or use a Hugo template partial. For privacy-friendly analytics, try Plausible or Umami (self-hosted or cloud).
How do I add a blog comment system?
Hugo is static, so comments need an external service. Options: Disqus (easiest, adds tracking), Utterances (GitHub Issues-based, open source), or Giscus (GitHub Discussions-based). Most themes have built-in Disqus support — just set disqusShortname in hugo.toml.

Next Steps

  • Add a GitHub Actions workflow to auto-deploy on push
  • Explore SEO optimization for your portfolio
  • Learn about CSS custom properties to theme your site
  • Check the Netlify documentation for advanced deployment features

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro