Building Your Portfolio & Blog with Hugo: From Zero to Deployed
Introduction: Why I Built This (And Why You Might Want To)
After years of saying “I should really have a blog,” I finally built one. Not on Medium. Not on Dev.to. A real, honest-to-goodness website that I control. And you know what? It was easier than I expected, once I stopped overthinking it.
This guide will show you how to build a portfolio and blog using Hugo, a static site generator that’s fast, flexible, and surprisingly beginner friendly. Whether you’re a developer looking for a weekend project or someone who’s never touched the command line, I’ve got you covered.
Fair warning: This gets detailed. Like, “here’s the exact command” detailed. Grab a coffee.
Table of Contents Quick Summary
- Non-Technical Track: Click-and-point focused, minimal terminal work
- Technical Track: Full control, command-line workflows, customization
- Theme Selection: How to choose and implement themes
- Content Creation: Adding posts, projects, and pages
- Deployment: Comparing GitHub Pages, Netlify, Vercel, and more
- Costs & Trade-offs: What’s free, what’s cheap, what’s worth it
Part 1: Understanding Hugo (The 5-Minute Version)
What is Hugo?
Hugo is a static site generator. Instead of querying a database every time someone visits your site (like WordPress does), Hugo pre-builds all your pages as HTML files. The result? Lightning-fast websites that cost almost nothing to host.
Think of it like this:
- WordPress: A restaurant that cooks your meal fresh every time you order
- Hugo: A meal prep service that cooks everything in advance and just heats it up when you’re ready
Why Hugo Over WordPress/Wix/Squarespace?
| Feature | Hugo | WordPress | Wix/Squarespace | ||
|---|---|---|---|---|---|
| Speed | Blazing fast | Moderate | Moderate | ||
| Cost | Free (hosting ~$0-5/mo) | $4-45/mo | $16-49/mo | ||
| Control | Complete | High | Limited | ||
| Security | Minimal risk | Requires updates | Managed | ||
| Learning Curve | Moderate | Low | Very low |
Hugo is perfect if you want:
- Full control over your site
- Near-zero hosting costs
- A developer-friendly workflow
- Lightning-fast page loads
Part 2: For the Non-Technical (I Promise, You Can Do This)
What You’ll Need
- A computer (Mac, Windows, Linux all work)
- 1-2 hours of focused time
- Willingness to copy-paste commands (I’ll provide them all)
- Optional: A GitHub account (free)
The Big Picture: Our 6-Step Plan
- Install Hugo on your computer
- Pick a theme (like choosing a WordPress theme, but better)
- Create your site structure
- Add your content (posts, about page, projects)
- Test it locally (see it on your computer first)
- Deploy it (make it live on the internet)
Step 1: Installing Hugo
On Mac:
Open Terminal (press
Cmd + Space, type “terminal”, press Enter)Install Homebrew (a package manager—think of it as an app store for developers):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"Install Hugo:
brew install hugoVerify it worked:
hugo versionYou should see something like
hugo v0.xxx.x
On Windows:
Option 1: Using Winget (Recommended if you are on Windows 11)
Winget is Microsoft’s official free and open-source package manager for Windows. To install the extended edition of Hugo:
- Open PowerShell or Command Prompt
- Install Hugo:
winget install Hugo.Hugo.Extended - Verify:
hugo version
Option 2: Using Chocolatey
- Install Chocolatey (if you don’t have it):
- Open PowerShell as Administrator
- Run:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
- Install Hugo:
choco install hugo-extended -y - Verify:
hugo version
On Linux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install hugo
Step 2: Choosing Your Theme
This is the fun part. Hugo has hundreds of free themes. Here’s how to choose:
Visit: https://themes.gohugo.io/
What to look for:
- Portfolio themes (if you want to showcase projects)
- Blog themes (if you’re mainly writing)
- Combined themes (like Hugo Profile, which I use and has both)
Popular recommendations:
| Theme | Best For | Difficulty |
|---|---|---|
| Hugo Profile | Developers, portfolios + blog | Easy |
| PaperMod | Minimalist blogs | Very Easy |
| Terminal | Developer blogs, retro look | Easy |
| Hugo-coder | Personal sites, clean design | Easy |
| Ananke | General-purpose | Very Easy |
For this guide, I’ll show both:
- Generic setup (works with any theme)
- Specific Hugo Profile setup (my theme)
Step 3: Creating Your Site
Open Terminal/Command Prompt and navigate to where you want your site folder:
# Navigate to your Documents folder (or anywhere you like)
cd ~/Documents
# Create a new Hugo site
hugo new site my-portfolio
# Enter the folder
cd my-portfolio
You now have a folder structure that looks like:
my-portfolio/
├── archetypes/
├── content/
├── data/
├── layouts/
├── static/
├── themes/
└── hugo.toml (or hugo.yml)
Step 4: Installing a Theme
Option A: Using Hugo Modules (Modern, Recommended)
Prerequisites: Install Go (Hugo modules need it)
On Mac:
brew install go
On Windows (with winget or chocolatey):
winget install -e --id GoLang.Go
Or
choco install golang
Initialize your site as a Hugo module:
hugo mod init github.com/yourusername/my-portfolio
Add a theme (using Hugo Profile as example):
Edit hugo.toml (or create hugo.yaml) and add:
baseURL: 'https://yourwebsite.com/'
languageCode: 'en-us'
title: 'Your Name - Portfolio'
theme: hugo-profile
module:
imports:
- path: github.com/gurusabarish/hugo-profile
Then run:
hugo mod get -u
Option B: Using Git Submodules (Traditional)
# Initialize git in your project
git init
# Add theme as submodule (example with Hugo Profile)
git submodule add https://github.com/gurusabarish/hugo-profile.git themes/hugo-profile
# Update hugo.yaml
echo "theme: hugo-profile" >> hugo.yaml
Step 5: Configuring Your Site
Open hugo.yaml in any text editor (VS Code, Notepad, TextEdit).
Basic configuration for Hugo Profile:
baseURL: 'https://yourname.com/'
languageCode: 'en-us'
title: 'Your Name - Portfolio & Blog'
theme: hugo-profile
# Enable emoji support
enableEmoji: true
# Output formats
outputs:
home:
- HTML
- RSS
- JSON
# Markdown settings
markup:
goldmark:
renderer:
unsafe: true
# Site parameters
params:
title: 'Your Name'
description: 'Your site description'
favicon: '/images/fav.png'
# Theme settings
useBootstrapCDN: false
animate: true
theme:
disableThemeToggle: false
defaultTheme: 'light' # or 'dark'
# Navbar
navbar:
align: ms-auto
brandName: 'Your Name'
disableSearch: false
menus:
disableAbout: false
disableExperience: false
disableEducation: false
disableProjects: false
disableAchievements: false
disableContact: false
# Hero section
hero:
enable: true
title: 'Hi, I am Your Name'
subtitle: 'I build things for the web'
content: 'A passionate developer. I tend to make use of modern technologies to build websites and applications.'
image: /images/hero.png
socialLinks:
fontAwesomeIcons:
- icon: fab fa-github
url: https://github.com/yourusername
- icon: fab fa-linkedin
url: https://linkedin.com/in/yourprofile
- icon: fab fa-twitter
url: https://twitter.com/yourhandle
# Footer
footer:
socialNetworks:
github: https://github.com/yourusername
linkedin: https://linkedin.com/in/yourprofile
twitter: https://twitter.com/yourhandle
Step 6: Adding Content
Create an About Page:
hugo new about.md
Open content/about.md and edit:
---
title: 'About Me'
date: 2025-12-21
draft: false
---
## Hi, I'm Your Name
I'm a [your profession] who loves [your interests].
### What I Do
- Thing 1
- Thing 2
- Thing 3
### My Journey
Write your story here...
### Get in Touch
- Email: your@email.com
- LinkedIn: [Your Profile](https://linkedin.com/in/yourprofile)
Create Your First Blog Post:
hugo new posts/my-first-post.md
Edit content/posts/my-first-post.md:
---
title: 'My First Post'
date: 2025-12-21
draft: false
tags: ['introduction', 'blogging']
---
## Welcome to My Blog
This is my first post. Here's why I'm starting this blog...
### What I'll Write About
- Topic 1
- Topic 2
- Topic 3
Stay tuned!
Step 7: Preview Your Site Locally
hugo server -D
Open your browser and go to: http://localhost:1313
What the -D flag means: Shows draft posts too
To stop the server: Press Ctrl + C in Terminal
Step 8: Ready to Deploy?
Skip to the Deployment Options section below!
Part 3: For the Technical (Let’s Get Granular)
Prerequisites & Setup
System requirements:
- Hugo Extended (for SCSS/SASS support):
v0.112.0+ - Git:
v2.30+ - Go (for Hugo Modules):
v1.20+ - Node.js (for some themes):
v18+
Verify your environment:
hugo version # Should show "extended"
git --version
go version
node --version
Project Initialization with Best Practices
# Create project directory
mkdir -p ~/projects/portfolio && cd ~/projects/portfolio
# Initialize Hugo site
hugo new site . --force
# Initialize git
git init
echo "public/" >> .gitignore
echo "resources/" >> .gitignore
echo ".hugo_build.lock" >> .gitignore
echo "node_modules/" >> .gitignore
# Initialize as Go module (for Hugo modules)
hugo mod init github.com/yourusername/portfolio
# Initialize npm (if theme requires it)
npm init -y
Hugo Modules vs Git Submodules vs Manual Installation
Comparison:
| Method | Pros | Cons | Best For |
|---|---|---|---|
| Hugo Modules | Auto-updates, clean, no git submodule pain | Requires Go | Production sites |
| Git Submodules | Version control, traditional | Clunky updates | Team projects |
| Manual | Full control | Manual updates | Heavy customization |
Hugo Modules Setup (Recommended):
# hugo.yaml
module:
imports:
- path: github.com/gurusabarish/hugo-profile
# Install/update theme
hugo mod get -u
# Tidy dependencies
hugo mod tidy
Git Submodules Setup:
git submodule add --depth=1 https://github.com/gurusabarish/hugo-profile.git themes/hugo-profile
git submodule update --init --recursive
# Update submodule later
git submodule update --remote --merge
Advanced Hugo Configuration
hugo.yml with full config:
baseURL: 'https://yourdomain.com/'
languageCode: 'en-us'
title: 'Your Portfolio'
theme: 'your-theme' # Only if using git submodule
# Build settings
buildDrafts: false
buildFuture: false
buildExpired: false
# Output formats
outputs:
home:
- HTML
- RSS
- JSON # For search functionality
# Markdown rendering
markup:
goldmark:
renderer:
unsafe: true # Allow raw HTML in markdown
highlight:
codeFences: true
guessSyntax: true
lineNos: true
style: monokai
tableOfContents:
startLevel: 2
endLevel: 6
ordered: false
# Taxonomies
taxonomies:
tag: tags
category: categories
series: series
# Privacy settings
privacy:
googleAnalytics:
respectDoNotTrack: true
twitter:
enableDNT: true
# Minification
minify:
disableXML: true
minifyOutput: true
# Caching
caches:
assets:
dir: :resourceDir/_gen
maxAge: '24h'
getjson:
dir: :cacheDir/:project
maxAge: '1h'
# Parameters (theme-specific)
params:
author:
name: 'Your Name'
email: 'your@email.com'
image: 'images/author.jpg'
# Features
features:
portfolio:
enable: true
blog:
enable: true
darkMode:
enable: true
default: system
# SEO
description: 'Your site description for SEO'
keywords: ['keyword1', 'keyword2']
images: ['images/og-image.jpg']
# Analytics (example: GoatCounter - privacy-friendly)
analytics:
goatCounter:
code: 'your-code'
# Social
social:
github: 'yourusername'
linkedin: 'yourprofile'
twitter: 'yourhandle'
Content Organization Strategies
Recommended structure:
content/
├── _index.md # Homepage content
├── about.md # About page
├── posts/ # Blog posts
│ ├── _index.md
│ ├── 2025/
│ │ ├── my-first-post/
│ │ │ ├── index.md
│ │ │ └── images/
│ │ │ └── hero.jpg
│ │ └── another-post.md
├── projects/ # Portfolio projects
│ ├── _index.md
│ ├── project-alpha/
│ │ └── index.md
│ └── project-beta.md
└── notes/ # Quick notes/TILs
├── _index.md
└── 2025-12-21-til.md
Page bundles (recommended for posts with images):
posts/
└── my-post/
├── index.md # Content
├── hero.jpg # Featured image
└── diagram.png # Inline image
Reference in markdown:

Frontmatter best practices:
---
title: 'Your Post Title'
date: 2025-12-21T14:30:00Z
lastmod: 2025-12-21T16:00:00Z
draft: false
author: 'Your Name'
# SEO
description: 'A concise description (150-160 chars) for search engines'
keywords: ['keyword1', 'keyword2']
# Taxonomy
tags: ['tag1', 'tag2']
categories: ['Category']
series: ['Series Name'] # For multi-part posts
# Images
images:
- 'posts/my-post/hero.jpg' # OG image
# Table of contents
toc:
enable: true
auto: true
# Comments (if using)
comments: true
# Math support (if needed)
math: true
# Code highlighting
highlight: true
# Custom params (theme-dependent)
hero: 'hero.jpg'
menu:
sidebar:
name: 'Display Name'
identifier: 'unique-id'
weight: 100
---
Creating Archetypes (Content Templates)
Create archetypes/posts.md:
---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
date: {{ .Date }}
draft: true
author: "Your Name"
description: ""
tags: []
categories: []
toc:
enable: true
# hero: images/posts/{{ .File.ContentBaseName }}/hero.jpg
---
## Introduction
Why this topic matters...
## Main Content
Your content here...
## Conclusion
Key takeaways...
## Resources
- [Resource](https://example.com)
Usage:
hugo new posts/my-new-post.md
# Auto-fills template
Custom Shortcodes
Create layouts/shortcodes/note.html:
<div class="note"><strong>Note:</strong> {{ .Inner | markdownify }}</div>
Use in markdown:
{{< note >}}
This is an important note!
{{< /note >}}
Local Development Workflow
# Standard dev server
hugo server -D
# With drafts, future posts, and live reload
hugo server -D -F --navigateToChanged
# Bind to all interfaces (access from phone on same network)
hugo server -D --bind 0.0.0.0
# Fast render mode (disables some features)
hugo server --disableFastRender
# Clean build
rm -rf public resources && hugo
Performance Optimization
Image optimization:
Install ImageMagick:
brew install imagemagick
Optimize images before adding:
# Resize large images
mogrify -resize 1920x1080\> -quality 85 -format jpg *.png
# Convert to WebP
for file in *.jpg; do
cwebp -q 80 "$file" -o "${file%.jpg}.webp"
done
Use Hugo’s image processing:
{{ $img := resources.Get "images/hero.jpg" }}
{{ $optimized := $img.Resize "800x q80" }}
<img src="{{ $optimized.RelPermalink }}" alt="Hero">
Version Control Best Practices
.gitignore template:
# Hugo build files
public/
resources/
.hugo_build.lock
# OS files
.DS_Store
Thumbs.db
# Editor files
.vscode/
.idea/
*.swp
# Dependencies
node_modules/
package-lock.json
# Environment files
.env
.env.local
Git workflow:
# Initial commit
git add .
git commit -m "Initial Hugo site setup"
# Create GitHub repo (using gh CLI)
gh repo create portfolio --public --source=. --remote=origin
git push -u origin main
# Regular workflow
git add .
git commit -m "Add new post: Building with Hugo"
git push
Part 4: Theme Selection Deep Dive
Evaluating Themes
Key criteria:
- Documentation quality - Can you figure out how to configure it?
- Last updated - Is it maintained? (Check GitHub)
- Features - Portfolio? Blog? Both? Dark mode? Search?
- Performance - Check Lighthouse scores on demo sites
- Customization - Can you easily override layouts?
- Dependencies - Does it require Node, PostCSS, etc.?
Popular Themes Breakdown
1. Hugo Profile (My Choice)
- Best for: Developer portfolios with blog
- Features: Hero section, About, Experience, Education, Projects, Achievements, Blog, Contact form, Light/Dark mode
- Tech: Bootstrap, Font Awesome
- Customization: YAML configuration files
- Setup complexity: Easy
- Hugo version required: 0.87.0+
- GitHub: https://github.com/gurusabarish/hugo-profile
- Demo: https://hugo-profile.netlify.app
Quick start with Git Submodule:
# Initialize git
git init
# Add theme as submodule
git submodule add https://github.com/gurusabarish/hugo-profile.git themes/hugo-profile
git submodule update --init --recursive
Or with Hugo Modules:
hugo mod init github.com/yourusername/portfolio
# hugo.yaml
baseURL: 'https://yourwebsite.com/'
languageCode: 'en-us'
title: 'Your Name - Portfolio'
theme: hugo-profile # Only for submodule method
# For Hugo modules, add:
module:
imports:
- path: github.com/gurusabarish/hugo-profile
outputs:
home:
- HTML
- RSS
- JSON
markup:
goldmark:
renderer:
unsafe: true
params:
title: 'Your Name'
description: 'Software Engineer | Developer'
favicon: '/images/fav.png'
useBootstrapCDN: false
animate: true
theme:
disableThemeToggle: false
defaultTheme: 'light'
# Hero section
hero:
enable: true
intro: 'Hi, my name is'
title: 'Your Name'
subtitle: 'I build things for the web'
content: 'A passionate developer focused on creating impactful digital experiences.'
image: /images/hero.png
socialLinks:
fontAwesomeIcons:
- icon: fab fa-github
url: https://github.com/yourusername
- icon: fab fa-linkedin
url: https://linkedin.com/in/yourprofile
# About section
about:
enable: true
title: 'About Me'
image: '/images/me.png'
content: |
I am a software developer with a passion for web development.
skills:
enable: true
title: 'Here are a few technologies I work with:'
items:
- 'React'
- 'Node.js'
- 'Python'
- 'Docker'
# Experience section
experience:
enable: true
items:
- job: 'Senior Software Engineer'
company: 'Company Name'
companyUrl: 'https://example.com'
date: 'Jan 2022 - Present'
content: 'Description of your role and achievements'
# Projects section
projects:
enable: true
items:
- title: 'Project Name'
content: 'Project description'
image: /images/projects/project.png
links:
- icon: fab fa-github
url: https://github.com/yourusername/project
# Blog configuration
# Create posts in content/blogs/
# Contact section
contact:
enable: true
email: your@email.com
btnName: 'Contact me'
Content structure:
content/
└── blogs/ # Blog posts go here
└── my-post.md
static/
└── images/
├── hero.png
├── me.png
└── projects/
Creating blog posts:
hugo new content/blogs/my-first-post.md
2. PaperMod
- Best for: Minimalist blogs
- Features: Fast, clean, search, dark mode
- Setup complexity: Low
- GitHub: https://github.com/adityatelange/hugo-PaperMod
Install:
git submodule add https://github.com/adityatelange/hugo-PaperMod themes/PaperMod
echo "theme = 'PaperMod'" >> hugo.toml
3. Terminal
- Best for: Retro/hacker aesthetic
- Features: Unique design, monospace fonts
- Setup complexity: Low
4. Anatole
- Best for: Personal blogs with photo focus
- Features: Beautiful typography, sidebar
- Setup complexity: Low
5. Clarity
- Best for: Technical documentation + blog
- Features: Search, syntax highlighting, mobile-first
- Setup complexity: Medium
Customizing Themes
Override layouts:
Create layouts/ directory matching theme structure:
layouts/
├── _default/
│ ├── baseof.html # Override base template
│ └── single.html # Override single post
├── partials/
│ ├── head.html # Override head
│ └── footer.html # Override footer
└── index.html # Override homepage
Custom CSS:
Create assets/css/custom.css:
/* Your custom styles */
.custom-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
Reference in config:
params:
customCSS: ['css/custom.css']
Part 5: Deployment Options (The Comparison You’ve Been Waiting For)
Quick Comparison Table
| Platform | Cost | Ease of Setup | Performance | Custom Domain | Analytics | Best For | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| GitHub Pages | Free | Easy | Good | Yes (free) | Via 3rd party | Developers | ||||||
| Netlify | Free tier | Very Easy | Excellent | Yes (free) | Yes | Everyone | ||||||
| Vercel | Free tier | Very Easy | Excellent | Yes (free) | Yes | Developers | ||||||
| Cloudflare Pages | Free | Easy | Excellent | Yes (free) | Yes | Privacy-focused | ||||||
| AWS S3 + CloudFront | ~$1-5/mo | Complex | Excellent | Yes ($12/yr) | Via CloudWatch | Enterprise | ||||||
| Firebase Hosting | Free tier | Medium | Excellent | Yes (free) | Yes | Firebase users | ||||||
| Render | Free tier | Easy | Good | Yes (free) | No | Simple deploys |
Detailed Deployment Guides
Option 1: GitHub Pages (My Setup)
Pros:
- Completely free
- Automatic deployments on git push
- Reliable (backed by GitHub)
- Easy custom domain setup
Cons:
- Public repos only (free tier)
- Build time limits
- No serverless functions
Setup Steps:
1. Create GitHub Repository
# If you haven't already
git init
git add .
git commit -m "Initial commit"
# Create repo using GitHub CLI
gh repo create portfolio --public --source=. --remote=origin --push
# Or manually: Go to github.com/new
2. Create GitHub Actions Workflow
Create .github/workflows/deploy.yml:
name: Deploy Hugo site to Pages
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: 'pages'
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.120.4
steps:
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Install Node.js dependencies
run: '[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true'
- name: Build with Hugo
env:
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
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
3. Enable GitHub Pages
- Go to your repo on GitHub
- Settings → Pages
- Source: GitHub Actions
- Save
4. Push and Deploy
git add .github/workflows/deploy.yml
git commit -m "Add GitHub Actions workflow"
git push
Your site will be live at: https://yourusername.github.io/portfolio/
5. Custom Domain (Optional)
Buy a domain (Namecheap, Google Domains, Cloudflare - ~$10-15/year)
Add to GitHub:
- Repo Settings → Pages → Custom domain
- Enter your domain (e.g.,
yourdomain.com) - Save
Configure DNS (example: Cloudflare):
Add these DNS records:
Type: A
Name: @
Content: 185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
Type: CNAME
Name: www
Content: yourusername.github.io
Update hugo.yml:
baseURL: 'https://yourdomain.com/'
Option 2: Netlify (Easiest for Non-Developers)
Pros:
- Extremely easy setup
- Automatic builds
- Form handling
- Serverless functions
- Deploy previews for PRs
- Built-in analytics (paid)
Cons:
- Build minute limits (free: 300/month)
- Bandwidth limits (free: 100GB/month)
Setup Steps:
1. Sign Up
Go to netlify.com → Sign up with GitHub
2. Deploy
- “Add new site” → “Import an existing project”
- Connect to GitHub
- Select your repository
- Build settings:
- Build command:
hugo --gc --minify - Publish directory:
public - Advanced: Add environment variable:
HUGO_VERSION:0.120.4
- Build command:
- Deploy site
3. Custom Domain
- Domain settings → Add custom domain
- Follow DNS instructions
- Enable HTTPS (automatic)
netlify.toml (optional, for more control):
[build]
publish = "public"
command = "hugo --gc --minify"
[build.environment]
HUGO_VERSION = "0.120.4"
HUGO_ENV = "production"
HUGO_ENABLEGITINFO = "true"
[context.production.environment]
HUGO_ENVIRONMENT = "production"
[context.deploy-preview]
command = "hugo --gc --minify --buildFuture -b $DEPLOY_PRIME_URL"
[context.branch-deploy]
command = "hugo --gc --minify -b $DEPLOY_PRIME_URL"
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
[[headers]]
for = "/*.css"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/*.js"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
Option 3: Vercel
Pros:
- Excellent performance
- Edge network
- Great developer experience
- Analytics (paid)
Cons:
- Commercial sites require paid plan
Setup:
- Go to vercel.com
- Import Git Repository
- Framework Preset: Hugo
- Deploy
vercel.json (optional):
{
"build": {
"env": {
"HUGO_VERSION": "0.120.4"
}
}
}
Option 4: Cloudflare Pages
Pros:
- Cloudflare’s global network
- Unlimited bandwidth (free)
- Privacy-focused
- Web analytics included
Cons:
- Newer platform (fewer integrations)
Setup:
- dash.cloudflare.com → Pages
- Connect GitHub
- Select repo
- Build settings:
- Build command:
hugo - Build output:
public - Environment variable:
HUGO_VERSION = 0.120.4
- Build command:
- Deploy
Option 5: AWS S3 + CloudFront (For the Over-Engineers)
Pros:
- Enterprise-grade
- Full control
- Can handle massive traffic
Cons:
- Complex setup
- Costs money (minimal, but not free)
- Requires AWS knowledge
Estimated costs: $1-3/month for small sites
High-level steps:
- Create S3 bucket
- Enable static website hosting
- Build Hugo site locally:
hugo --gc --minify - Upload
public/to S3:aws s3 sync public/ s3://your-bucket - Create CloudFront distribution
- Configure Route53 for custom domain
- Set up SSL certificate (free via ACM)
Not recommended unless you’re already in AWS ecosystem.
My Recommendation
| Your Situation | Best Choice |
|---|---|
| Developer with GitHub | GitHub Pages |
| Complete beginner | Netlify |
| Want best performance | Vercel or Cloudflare Pages |
| Privacy-conscious | Cloudflare Pages |
| Need forms/functions | Netlify |
| Enterprise/scale | AWS or Cloudflare |
My setup: GitHub Pages + Cloudflare (for DNS and caching)
Part 6: Adding Features
Analytics (Privacy-Friendly)
Options:
GoatCounter (Free, open-source, privacy-friendly)
params: analytics: goatCounter: code: 'yourcode'Sign up: goatcounter.com
Plausible (Paid, privacy-focused, beautiful UI) ~$9/month for 10k pageviews
Cloudflare Web Analytics (Free, privacy-first) Add script to
layouts/partials/head.html
Comments
Options:
Giscus (GitHub Discussions-powered, free)
- Enable Discussions on your repo
- Configure at giscus.app
- Add script to layouts
Utterances (GitHub Issues-powered)
Disqus (Traditional, but privacy concerns)
Search
For static sites:
Built-in JSON index
outputs: home: - HTML - RSS - JSONFuse.js (client-side search)
Algolia (external service, free tier available)
Contact Forms
Options:
Netlify Forms (if on Netlify)
<form name="contact" method="POST" data-netlify="true"> <input type="email" name="email" required /> <textarea name="message" required></textarea> <button type="submit">Send</button> </form>Formspree (free tier: 50/month)
Google Forms (embed)
Part 7: Content Writing Tips
Post Structure That Works
- Hook - Why should I care?
- Context - What’s the background?
- Main content - The meat
- Visuals - Code, diagrams, screenshots
- Conclusion - Key takeaways
- Resources - Further reading
SEO Basics
# In frontmatter
title: 'Clear, descriptive title with keywords'
description: '150-160 char description for Google preview'
keywords: ['keyword1', 'keyword2']
images: ['path/to/og-image.jpg'] # For social shares
Create layouts/partials/seo.html:
<meta name="description" content="{{ .Description }}" />
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ .Description }}" />
<meta
property="og:image"
content="{{ .Site.BaseURL }}{{ index .Params.images 0 }}"
/>
<meta name="twitter:card" content="summary_large_image" />
Code Syntax Highlighting
Hugo has built-in syntax highlighting:
```python
def hello():
print("Hello, world!")
```
**Configure in `hugo.yml`:**
```yaml
markup:
highlight:
codeFences: true
guessSyntax: true
lineNos: true
style: monokai # or: github, dracula, etc.
Part 8: Maintenance & Workflow
Regular Tasks
Weekly:
- Write content
- Push to GitHub (auto-deploys)
Monthly:
- Update Hugo:
brew upgrade hugo - Update theme:
hugo mod get -u - Check analytics
- Respond to comments
Quarterly:
- Review old posts for updates
- Check broken links
- Audit performance (Lighthouse)
Backup Strategy
Your site is already backed up (it’s in GitHub!), but:
# Clone to another location periodically
git clone https://github.com/yourusername/portfolio.git backup-portfolio
# Or use GitHub's export feature
Content Ideas When You’re Stuck
- TIL (Today I Learned) posts
- Bug fixes you solved
- Tutorials you wish existed
- Book/course reviews
- Project retrospectives
- Tools you use
- Career reflections
- “How I built this” posts (like this one!)
Part 9: Troubleshooting Common Issues
“Hugo command not found”
Solution: Reinstall Hugo or add to PATH
# Mac
brew install hugo
# Verify
which hugo
“Theme not found”
Solution:
- Check
hugo.ymlhas correct theme name - For modules:
hugo mod get -u - For submodules:
git submodule update --init --recursive
“Site looks broken locally”
Solution: Check baseURL
# hugo.yml - for local dev, use:
baseURL: 'http://localhost:1313/'
# Or use environment-specific:
# baseURL: '/' # Hugo will use current URL
“Images not showing”
Solution:
- Images go in
static/orassets/ - Reference from markdown:
/images/photo.jpg - Or use page bundles (see above)
“Build failing on Netlify/Vercel”
Common causes:
- Wrong Hugo version
- Missing environment variables
- Theme not properly installed
Solution: Check build logs, set HUGO_VERSION variable
Conclusion: You’re Ready to Build
Building a portfolio and blog with Hugo might seem intimidating, but it’s actually pretty straightforward once you get past the initial setup. Here’s what makes it worth it:
- Performance: Your site will be blazing fast
- Cost: Free to nearly free
- Control: You own your content and platform
- Learning: You’ll understand how the web works
- Flexibility: Endless customization possibilities
Your Next Steps
- Pick your path: Non-technical or technical guide above
- Choose a theme: Browse themes.gohugo.io
- Set up locally: Follow the installation steps
- Write your first post: Use the template
- Deploy: Choose GitHub Pages or Netlify
- Share: Post on LinkedIn, Twitter, wherever
What I Wish I Knew Starting Out
- Start simple, customize later
- Perfect is the enemy of shipped
- Writing is harder than setup (allocate time accordingly)
- Your first posts will be rough—that’s okay
- The community is helpful (Hugo Discourse, Reddit)
Resources
Official Documentation
Tools I Use
- Editor: VS Code with Hugo extension
- Markdown: Markdown Guide
- Images: TinyPNG for compression
- Diagrams: Excalidraw
- Icons: Font Awesome
Learning Resources
Hosting Comparisons
One More Thing
If you build your portfolio using this guide, I’d genuinely love to see it. Send me a link at contact@puneeth.io or tag me on LinkedIn. Seriously—seeing what people build makes my day.
And if you get stuck? The Hugo community is incredibly helpful. Post on the Discourse forum and you’ll usually get help within hours.
Now stop reading and start building. Your future self will thank you.
Questions? Stuck somewhere? Reach out at contact@puneeth.io
This post will be updated periodically as Hugo evolves and I learn new tricks. Last updated: December 2025
