Skip to content

How to migrate from WordPress to Hugo

How do you migrate a WordPress site to Hugo (static site generator)?

HardEstimated time: 1-3 daysModerate data-loss riskFrom: wordpress To: hugo

Why migrate from WordPress to Hugo?

WordPress-to-Hugo is the most aggressive simplification path available for a content site. WordPress is a PHP application talking to MySQL on every request; Hugo is a Go binary that produces flat HTML files. The static output deploys to any CDN (Cloudflare Pages, Netlify, S3 + CloudFront) for cents per month, has zero attack surface for plugin CVEs, and serves in single-digit milliseconds at the edge.

The trade is ergonomics. WordPress's admin gives a non-technical editor a what-you-see-is-what-you-get UI; Hugo gives you a filesystem of Markdown files and a Git workflow. Every dynamic feature -- search, comments, contact forms, member areas -- requires a separate third-party JavaScript service or a separate backend. Hugo is the right answer when content is the entire product and the editorial team is comfortable with Markdown + Git.

The other gotcha: theme migration is rewrite, not port. Hugo themes are Go templates with a specific shape; WordPress themes are PHP. Plan on either using a stock Hugo theme or a 1-2 week rebuild of your design.

Before you start

  • Pick your hosting. Cloudflare Pages, Netlify, Vercel, or GitHub Pages all serve Hugo output for free or near-free. Build-on-push from GitHub is the canonical workflow.
  • Pick a theme. themes.gohugo.io has 400+ options. Filter by "blog" + look for active maintenance.
  • Backup. Full WordPress DB + wp-content/uploads. Same as any cutover.

Step-by-step migration

1. Install the WordPress-to-Hugo exporter

Two reasonable tools:

  • wp2hugo (Go binary) -- runs against the WordPress REST API remotely; no plugin install needed.
  • wordpress-to-hugo-exporter PHP plugin -- runs inside WordPress, downloads a tarball.

The plugin path is most common:

wp plugin install wordpress-to-hugo-exporter --activate
# Then in WP admin: Tools -> Export to Hugo -> download .zip

The output is a directory tree:

content/
  posts/
    2024-04-15-my-post.md
  pages/
    about.md
static/
  uploads/
    2024/04/header.jpg

Each .md has YAML frontmatter (title, date, tags, categories, featured_image).

2. Initialise a Hugo site

hugo new site mysite
cd mysite
git init
git submodule add https://github.com/your-theme/hugo-theme themes/yourtheme
echo "theme = 'yourtheme'" >> hugo.toml

Drop the exported content/ and static/ over the empty Hugo defaults.

3. Run Hugo locally

hugo server -D

Visit http://localhost:1313. Walk through every section + every post type. Common breakage:

  • Featured-image paths may need a search-and-replace (/wp-content/uploads/ -> /uploads/).
  • Shortcodes like [gallery] won't render -- replace with Hugo shortcodes or plain HTML.
  • Categories vs tags semantics differ; check theme expectations.

4. Set up redirects

Same as the Ghost migration: WordPress's /2024/04/my-post/ becomes Hugo's /posts/my-post/ (default theme) or /my-post/ (if you set permalinks in hugo.toml).

In Cloudflare Pages, use a _redirects file at the project root:

/2024/:month/:post  /posts/:post  301

In Netlify, same syntax. In GitHub Pages, use a JS-based redirect in a one-off HTML page per old URL (less clean -- prefer a host that supports server-side redirects).

5. Build + deploy

hugo --minify
# output is in ./public

Push to your host. Build-on-push from GitHub is the canonical workflow:

# .github/workflows/deploy.yml
- uses: peaceiris/actions-hugo@v2
  with: { hugo-version: 'latest' }
- run: hugo --minify
- uses: peaceiris/actions-gh-pages@v3
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_dir: ./public

6. Replace dynamic features with static-friendly alternatives

  • Search: Pagefind, lunr.js, or Algolia DocSearch.
  • Comments: Disqus, Giscus (GitHub Discussions), Cusdis.
  • Forms: Formspree, Tally, Cloudflare Workers handler.
  • Newsletter: Buttondown, ConvertKit signup form.

What doesn't migrate automatically

  • WooCommerce + any e-commerce primitive.
  • Membership plugins (Restrict Content Pro, MemberPress) -- Hugo has no auth layer.
  • Comments (lost; bridge to Disqus or accept the loss).
  • WordPress search box (replace with Pagefind).
  • Custom post types beyond simple posts + pages.

Common pitfalls

  • Theme rebuild is the hidden cost. Plan a week, not an afternoon. Hugo themes have specific layout assumptions (which partials they expect, what data the Site object exposes); a WordPress theme designer can't drop a PSD and expect Hugo to render it.
  • Image paths break. Run a search-and-replace across exported .md files before commit (/wp-content/uploads/ -> /uploads/).
  • Drafts get exported. Filter draft: true posts in your build pipeline (hugo --buildDrafts=false, the default).
  • Author taxonomy doesn't survive cleanly. Hugo's default theme uses a single author; WordPress's Author field becomes a string with no link. Plan accordingly.

How BeaverCheck measures the difference

Avg performance: wordpress vs hugoAvg performance: wordpress vs hugo0255075100wordpresshugo

We've audited 713 WordPress sites and 33 Hugo sites. Average Lighthouse performance: WordPress 45 / 100, Hugo 69 / 100, a difference of +24 points.

The static-output gap is real and measurable. Run a free audit on your current WordPress site to see the numbers before committing to the move.

Further reading

Related migrations

Send Feedback