This is how derek.engineer is wired: static Hugo site, PaperMod theme, Netlify deploys, Squarespace DNS, and a local writing workflow that keeps publishing from becoming its own project.
The stack
- Hugo — static site generator, fast builds, zero frontend dependencies
- PaperMod — clean Hugo theme, installed as a git submodule
- Netlify — deploys on every push to
main, custom domain + SSL handled automatically - GitHub — source of truth, all posts are Markdown files in
content/posts/
The flow is simple:
Write Markdown → commit → push to GitHub → Netlify builds and deploys → live in ~30 seconds
Why Hugo
I wanted a blog, not a project — no build pipeline to maintain, no CMS to update, no dependencies that rot. Markdown files in a git repo, deploy on push. Hugo does exactly that and nothing else. hugo server --buildDrafts spins up a live preview in under a second.
PaperMod for the theme — minimal, dark mode by default, readable code blocks. I didn’t need a custom design, I needed something I could ignore.
Netlify setup
The netlify.toml pins the Hugo version so the production build matches local:
[build]
command = "hugo"
publish = "public"
[build.environment]
HUGO_VERSION = "0.161.1"
Netlify picks this up automatically. New commit to main → deploys. No CI to configure, no Actions YAML, no deploy scripts.
Custom domain setup took a bit more than two minutes — here’s the actual detail.
DNS setup
The registrar is Squarespace. Netlify is just the deployment target. So the job was: tell Squarespace DNS to point traffic to Netlify.
Two hostnames matter: the apex domain (derek.engineer) and the subdomain (www.derek.engineer). They’re handled differently.
The www record is straightforward — a CNAME pointing to the Netlify site instance:
| Type | Name | Value |
|---|---|---|
| CNAME | www | wonderful-fox-6a6371.netlify.app |
The apex record is trickier. Apex domains can’t be a standard CNAME at most DNS providers. Netlify offers two options:
- Preferred: ALIAS record to
apex-loadbalancer.netlify.com - Fallback: A record to
75.2.60.5
Squarespace supports ALIAS, so that’s what I used:
| Type | Name | Value |
|---|---|---|
| ALIAS | @ | apex-loadbalancer.netlify.com |
The @ means the root domain itself.
One thing to watch: at one point there was also a derek.engineer → A → 75.2.60.5 record alongside the ALIAS. That’s the fallback option — valid but redundant when you have ALIAS working. Remove it so there’s one clear source of truth for the apex.
Final DNS shape:
@ ALIAS apex-loadbalancer.netlify.com
www CNAME wonderful-fox-6a6371.netlify.app
Once DNS propagated, Netlify verified both hostnames and provisioned the TLS certificate automatically. Until that finishes (~a few minutes), the browser will show “Not Secure” — expected, not broken.
Local writing workflow
The part that makes this setup useful in practice is CLAUDE.md.
Claude Code reads CLAUDE.md before working in the repo. Mine gives it the rules I would otherwise have to repeat every time:
- Front matter format with required fields
- File naming convention (kebab-case, descriptive)
- The publish workflow (
git add,git commit,git push) - Voice and tone guidelines
The result: when I finish a project, I can dump rough notes from the session, have Dex format them into a post, then review the actual Markdown before publishing.
That is the workflow I want: the source stays plain Markdown, the git history stays normal, and the writing assistant is just part of the local toolchain.
Enhancements added after launch
A few quick PaperMod features enabled after the initial setup:
Search — PaperMod ships with Fuse.js-based fuzzy search. Enabling it just required adding JSON to the Hugo output formats and creating a search.md page:
[outputs]
home = ["HTML", "RSS", "JSON"]
Archive — Chronological post list grouped by year/month. One archive.md page with layout: archives.
Table of contents — Auto-generated per post from headings. One line in hugo.toml:
ShowToc = true
Tags in nav — Already generating /tags/ pages, just needed a menu entry.
Netlify credit limits
One gotcha worth knowing: Netlify’s free tier gives you 300 credits/month, and each production deploy costs 15 credits. That’s 20 deploys per month.
Every git push to main triggers a deploy. If you’re iterating — pushing small fixes, tweaks, and content changes separately — you’ll burn through credits fast. I hit 180/300 in a single session by pushing every change individually.
The fix is simple: batch changes locally and push once per session. Commit as much as you want, just don’t push until you’re done with a logical chunk of work.
The gotcha
Netlify’s free tier gives 300 credits/month, 15 per deploy — 20 deploys total. I burned 180 in one session pushing every small fix separately. Now I batch and push once per session. Simple fix, but worth knowing before you hit it.
The CLAUDE.md file is the other thing worth stealing for any similar setup. It keeps the writing workflow explicit: front matter, file names, publish steps, and voice. Without that, the activation energy to write something up is too high and the blog dies.