Personal portfolio site for Nathan Healea — a static site built with Hugo and a custom in-repo theme (themes/nathanhealea). The site is a single-page layout assembled from partials (hero, stats, experience, projects, contact) driven by YAML data files and site params, deployed to Vercel.
- Live: https://nathanhealea.com
- Generator: Hugo (extended)
0.160.0 - Styling: hand-written CSS bundled through Hugo Pipes
- Scripts: ES modules bundled with
js.Build(esbuild) - No Node dependencies — there is no
package.json; Hugo does all the building
| Tool | Version | Notes |
|---|---|---|
| Hugo | 0.160.0 extended (min 0.110.0) |
Pinned in vercel.json via HUGO_VERSION; match it locally to avoid build drift |
| Git | any recent |
Node.js is not required. Hugo's embedded esbuild handles JavaScript bundling.
Make sure you install the extended edition.
macOS (Homebrew)
brew install hugoLinux / WSL (Snap)
sudo snap install hugoLinux / WSL (direct download — pins the exact version)
curl -LO https://github.com/gohugoio/hugo/releases/download/v0.160.0/hugo_extended_0.160.0_linux-amd64.tar.gz && tar -xzf hugo_extended_0.160.0_linux-amd64.tar.gz hugo && sudo install hugo /usr/local/bin/hugo && rm hugo hugo_extended_0.160.0_linux-amd64.tar.gzWindows (winget)
winget install Hugo.Hugo.ExtendedVerify the install — the output must contain +extended:
hugo versionClone the repository and enter it:
git clone https://github.com/NathanHealea/nathanhealea.com.gitcd nathanhealea.comThe theme lives inside the repo at themes/nathanhealea (it is not a git submodule), so there is nothing further to fetch or install.
Start the dev server with live reload and draft/future content visible:
hugo server -DThen open http://localhost:1313.
Useful variations:
hugo server -D --navigateToChangedhugo server --disableFastRender-Drenders content markeddraft: true.--navigateToChangedjumps the browser to the page you just edited.--disableFastRenderforces a full rebuild — use it when a partial or CSS change doesn't seem to take effect.
The dev server serves unminified, unfingerprinted CSS/JS. Minification and fingerprinting only happen in production builds (hugo.IsProduction).
Produce the production build into public/:
hugo --gc --minifyThis is the exact command Vercel runs. public/ is git-ignored.
Preview the production output locally:
hugo server --environment production --minify.
├── hugo.toml # Site config: baseURL, title, params, stats, SEO
├── vercel.json # Vercel build config (framework, build cmd, HUGO_VERSION)
├── archetypes/default.md # Front matter template for `hugo new`
├── content/_index.md # Home page front matter (title + description)
├── data/
│ ├── experience.yaml # Work history timeline entries
│ └── projects.yaml # Portfolio project cards
├── assets/ # Site-level assets (jsconfig.json is generated + ignored)
├── static/ # Files copied verbatim to the site root
├── i18n/ # Translation tables (currently unused)
├── layouts/ # Site-level template overrides (currently empty)
└── themes/nathanhealea/
├── theme.toml
├── layouts/
│ ├── _default/baseof.html # HTML shell, skip link, script bundling
│ ├── index.html # Home page — composes the section partials
│ └── partials/
│ ├── head.html # Meta, Open Graph, JSON-LD, CSS pipeline
│ ├── header.html footer.html
│ ├── hero.html stats.html experience.html projects.html contact.html
│ ├── components/ # badge-list, section-header, social-links,
│ │ # hire-status, contract-status
│ └── icons/ # github, linkedin, mail, external, arrow-right
└── assets/
├── css/
│ ├── base/ # tokens, reset, typography
│ ├── layout/ # container, section
│ ├── components/ # link, btn, badge, navbar, card, timeline, hero, stats, footer
│ ├── sections/ # projects, contact
│ └── utilities/ # reveal, helpers
└── js/
├── main.js # Entry point
└── modules/ # nav, reveal, hero-network
- CSS —
head.htmlholds an explicit ordered list of stylesheets and concatenates them withresources.Concatso the cascade order is deterministic. Adding a new CSS file requires adding its path to that$orderslice, or it will not be bundled. - JS —
baseof.htmlrunsassets/js/main.jsthroughjs.Build(esbuild, targetes2018). Import new modules frommain.js; no build config to edit. - In production both bundles are minified and fingerprinted with subresource integrity hashes.
Most day-to-day changes are config or data edits — no templates required.
| Param | Purpose |
|---|---|
title, baseURL |
Site identity |
params.description, params.seo.keywords |
Meta description and keywords |
params.author, params.location, params.headline, params.tagline |
Identity shown across the page |
params.heroSubtitle |
Hero paragraph copy |
params.github, params.linkedin, params.email |
Social/contact links |
params.stats |
Repeatable [[params.stats]] blocks (value, desc) for the stats band |
params.available.hire / params.available.contract |
Toggle the availability badges on or off |
params.hire.position, params.hire.roles |
Seniority and role list shown when available.hire is true |
- company: University of Oregon
title: Analyst Programmer II
location: Eugene, OR
start: Jan 2023
end: Present
current: true
highlights:
- Bullet describing an accomplishment
tech: [Drupal, PHP, Node.js]Entries render top-to-bottom in file order — newest first.
- title: grimify.app
slug: grimify
icon: "🎨"
description: "One-paragraph summary of the project."
tech: [TypeScript, React, Node.js]
github: https://github.com/NathanHealea/grimify.app
live: https://grimify.app
featured: truelive is optional — omit it for projects without a public deployment. featured controls prominence in the projects grid.
hugo new content/about.mdThe site sets disableKinds = ["taxonomy", "term"], so tags and categories are not generated.
The site deploys to Vercel from main. vercel.json pins the setup:
{
"framework": "hugo",
"buildCommand": "hugo --gc --minify",
"outputDirectory": "public",
"build": { "env": { "HUGO_VERSION": "0.160.0" } }
}Pushing to main triggers a production deploy; pull requests get preview deploys. When bumping Hugo locally, update HUGO_VERSION in vercel.json to match.
A CSS change has no effect. Confirm the file's path is listed in the $order slice in themes/nathanhealea/layouts/partials/head.html, then restart the server with --disableFastRender.
hugo version doesn't say +extended. Reinstall the extended edition — see Installing Hugo.
Stale output after a rename or delete. Remove the build cache and output, then rebuild:
rm -rf public resources/_gen && hugo --gc --minifyPort 1313 already in use.
hugo server -D --port 1414The theme is MIT licensed (see themes/nathanhealea/theme.toml). Site content — copy, resume details, and project descriptions — is © Nathan Healea.