Setting Up a Hugo Blog on Netlify (The Easy Way)

Table of Contents

In my last post I walked through hosting a Hugo blog on AWS S3 with CloudFront. It works, but let’s be honest — it’s a lot of moving parts. S3 bucket, CloudFront distribution, IAM policies, DNS records, cache invalidation. If your blog is the only thing on the line, that’s a fair bit of overhead.

A few people asked whether there’s a simpler way. There is.

This post covers hosting the same Hugo blog on Netlify — the zero-config, free HTTPS, push-to-deploy alternative.

Markdown → Hugo Build → Netlify Deploy → blog.example.com

One service. No bucket policies. No CloudFront invalidation. Just push and it works.


Why Netlify?

FeatureAWS S3 + CloudFrontNetlify
Setup complexityMediumZero
Custom domainManual DNS + ACMAutomatic SSL
Deploy methodCLI syncGit push or drag-and-drop
Cache invalidationManualInstant (new deploy)
Preview URLsNoYes (per-PR)
Free tier cost~$1-2/monthFree
CI/CD pipelineBuild yourselfBuilt-in

If you just want your blog live and forgotten, Netlify is the way.


Prerequisites

  • A Netlify account (free)
  • Your Hugo site built (hugo --minify)
  • Your domain (e.g., blog.example.com) with DNS managed anywhere (Ionos, Cloudflare, wherever)

That’s it. No AWS account needed.


Step 1: Build Your Hugo Site

Same as before:

cd /workspace/hugo-blog
hugo --minify

This generates your public/ directory. That’s the folder Netlify deploys.


Install the CLI

npm install -g netlify-cli

Login

netlify login

This opens a browser for authentication. Once done, you’re authenticated locally.

Create the Site

cd /workspace/hugo-blog
netlify init

You’ll be prompted through a few questions:

  1. How do you want to set up this site? → “Set up & connect to a new site”
  2. What’s your team/org name? → (your account name)
  3. What’s your site name? → pick something like my-hugo-blog
  4. Base directory?public (this is crucial — tell Netlify to serve from public/)
  5. Build command?hugo --minify (or just leave blank if deploying pre-built files)
  6. Publish directory?public (confirm)

Netlify creates a netlify.toml file in your project root. It should look like:

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

The publish setting tells Netlify which folder contains your built site. The command tells it how to build — if you push source files instead of pre-built ones.

Deploy

netlify deploy --prod

This pushes your public/ folder to Netlify. You’ll get a live URL like https://random-name-12345.netlify.app.

Your blog is now live. Point it to your browser and check it out.


Step 2 (Alt): Deploy by Drag & Drop (No CLI)

If you don’t want to install anything:

  1. Build your site: hugo --minify
  2. Go to app.netlify.com
  3. Click SitesAdd new siteImport an existing projectDeploy manually
  4. Drag and drop your entire public/ folder onto the upload area

Done. Netlify gives you a *.netlify.app URL instantly.

Note: The drag-and-drop method doesn’t give you CI/CD — every update means manually uploading again. The CLI method is better if you’ll be updating regularly.


Step 3: Connect a Git Repository (Automatic Deployments)

This is where Netlify really shines. Connect your Git repo and every push auto-deploys.

  1. Go to your site dashboard on Netlify
  2. Click Set up Continuous Deployment
  3. Choose your Git provider (GitHub, GitLab, Bitbucket)
  4. Authorize and pick your repository
  5. Configure the build settings:
    • Build command: hugo --minify
    • Publish directory: public
  6. Click Save

Now every time you push to your default branch, Netlify:

  1. Pulls your code
  2. Runs hugo --minify
  3. Deploys the result

You never have to think about deployment again. Write a post, push, it goes live in ~30 seconds.

Pro tip: If you’re already using Git (which you should be), this is a one-time setup that pays for itself immediately.


Step 3 (Alt): Preview Deployments

For every pull request, Netlify creates a unique preview URL. This is great if you want to:

  • Review posts before they go live
  • Share drafts with others
  • Test changes in production

Enable it in Site settingsBuild & deployPost-processingContinue as before (PR builds are on by default for connected repos).

When you open a PR, you get a comment with a preview URL like https://deploy-preview-42--my-hugo-blog.netlify.app.


Step 4: Set Up Your Custom Domain

On Netlify

  1. Go to Domain settings in your site dashboard
  2. Click Add custom domain
  3. Enter blog.example.com
  4. Click Verify

Netlify will automatically provision a free SSL certificate. This happens in seconds — no ACM, no certificate manager, no manual provisioning.

On Your DNS Provider (Ionos)

Log in to your Ionos Control Center and navigate to DNS → Records.

Add a CNAME Record

TypeHostValueTTL
CNAMEblograndom-name-12345.netlify.app (from Netlify)600

Or if you want to use the root domain (e.g., example.com), use a CNAME Flattening / ANAME record — Netlify provides an IP to point to.

Alternative: Use Netlify’s Nameservers

Netlify can also be your DNS provider:

  1. In Domain settings, click Add custom domain
  2. Enter your domain
  3. Click Use Netlify DNS
  4. Update your domain registrar’s nameservers to the ones Netlify provides

This gives you DNS management inside Netlify’s dashboard. Some people prefer this because everything is in one place.


Step 5: Configure Hugo for Netlify

There’s one important setting. Open hugo.toml and make sure your baseURL uses a relative path (no hardcoded domain):

baseURL = '/'

This is critical. If you hardcode https://blog.example.com, your local development and Netlify’s preview URLs will break. Keeping it as '/' means all links resolve relative to the current host — it works everywhere.


Step 6: Verify

Visit https://blog.example.com — your Hugo blog should load with full HTTPS, no configuration required on your part.

Netlify handles:

  • Automatic HTTP → HTTPS redirect
  • OCSP stapling
  • HSTS headers
  • Modern TLS ciphers

All free. All automatic.


Keeping It Updated

With Git integration set up, updating is trivial:

cd /workspace/hugo-blog
# Write your post in content/en/posts/
git add content/en/posts/my-new-post/index.md
git commit -m "Add my new post"
git push origin main

That’s it. Netlify detects the push, rebuilds, and deploys. You get:

  • A deployment log (check the Netlify dashboard)
  • A new URL if you want to share: https://<deploy-hash>--my-hugo-blog.netlify.app
  • Automatic URL invalidation (no manual cache clearing)

No hugo --minify on your machine. No aws s3 sync. No aws cloudfront create-invalidation.

Just git push.


The netlify.toml Configuration Reference

For more control, you can customize your netlify.toml. Here’s a production-ready version:

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

[build.environment]
  HUGO_VERSION = "0.162.0"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200
  force = true

What each part does:

SectionPurpose
publishWhich folder Netlify serves
commandHow to build (optional if you deploy pre-built)
HUGO_VERSIONPin Hugo version for reproducible builds
[[redirects]]SPA-style routing — redirects all 404s to index.html

Note on redirects: The catch-all redirect to index.html is needed if you want deep linking to work correctly on Netlify. Without it, refreshing a post URL directly might return a 404. This is a known Hugo + Netlify gotcha.


Bonus: Environment Variables

If you need environment-specific configuration (like analytics IDs, API keys, or different baseURL for staging):

  1. Go to Site settingsEnvironment variables
  2. Add variables like HUGO_BASEURL or GOOGLE_ANALYTICS
  3. Reference them in your Hugo templates:
    {{ with getenv "GOOGLE_ANALYTICS" }}
      <script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
    {{ end }}
    

Or set them in netlify.toml for consistent versions across environments:

[build.environment]
  HUGO_BASEURL = "https://blog.example.com"

Netlify vs S3: Honest Comparison

Here’s where I stand after using both:

Choose Netlify when:

  • You want simplicity. One service, zero config.
  • You value speed over control. Push to deploy in seconds.
  • You need preview URLs. Every PR gets a live preview.
  • You’re solo. No team, no compliance requirements, no enterprise needs.
  • Cost matters. Free tier covers ~100GB bandwidth/month — plenty for a blog.

Choose S3 + CloudFront when:

  • You already have AWS infrastructure. If you’re paying for AWS anyway, S3 is marginal cost.
  • You need fine-grained access control. S3 supports private buckets with CloudFront signed URLs.
  • You’re comfortable with AWS. If you already manage S3/CloudFront for other things, adding a blog is trivial.
  • You want to learn cloud infrastructure. There’s educational value in understanding S3 policies and CloudFront distributions.

The numbers

NetlifyS3 + CloudFront
Monthly cost$0~$1-2
Time to first deploy5 minutes30+ minutes
Time to updateGit push (automated)CLI command + invalidation
SSLAutomaticManual (ACM or CloudFront default)
CDNBuilt-inCloudFront
SupportCommunityAWS support (paid)

The $1-2/month on S3 is real, but compared to the time saved on Netlify, it’s not even a rounding error unless you’re hosting something massive.


Troubleshooting

404 on Post Pages

  • Make sure publish in netlify.toml points to public
  • Add the catch-all redirect (see netlify.toml reference above)
  • Rebuild and push: hugo --minify && netlify deploy --prod

Build Fails on Netlify

  • Check the Deploys tab — it shows the build log with error details
  • Make sure the Hugo version matches: add HUGO_VERSION to environment variables
  • Run hugo --minify locally first to verify it works

Custom Domain Not Working

  • Wait for DNS propagation (5-30 minutes usually)
  • Check your DNS provider for the correct CNAME value from Netlify
  • Verify SSL is provisioning: Domain settings → check for “Certificate provisioning” status

Blank Page / CSS Not Loading

  • Your baseURL in hugo.toml should be '/', not a hardcoded domain
  • Clear your browser cache — Netlify deploys instantly, but browsers cache aggressively

Wrapping Up

After running the S3 setup, the Netlify path feels almost too simple. But that’s the point — hosting a blog shouldn’t be a side project.

The Netlify pipeline is:

Write markdown → git push → blog updates

The S3 pipeline is:

Write markdown → hugo build → aws s3 sync → (optional) aws cloudfront invalidate → git push

Both work. Both put your content online. But one lets you focus on writing and the other on infrastructure.

For a personal blog? I’d pick Netlify every time.


Previous post: Setting Up a Hugo Blog on AWS S3 with Custom Domain