Your first Hugo build succeeds, but an old bookmark returns 404 and half the images are missing. The build checked whether it could render the new input. It didn’t know what the old site promised its readers.

We’ll migrate one representative post and turn those promises into checks before moving the whole collection.

Make an inventory before conversion

A content export is not a complete site backup. Keep the database and relevant files separately and verify your recovery method. The WordPress backup guide explains those components.

Choose a post containing a heading, image, code example, and internal link. Record its current public URL, referenced media URLs, title, publication state, and any redirects. This small specimen exposes more conversion problems than a paragraph of plain text.

The diagram treats normalization and verification as explicit stages between export and cutover.

From database pages to static filesA migration moves more than post text. Preserve media, metadata, and URL behavior, then verify the generated site before switching traffic. From database pages to static files FOLLOW THE ARROWSExportCapture posts and mediaNormalizeContent, links, metadataHugo buildRender templatesStatic outputVerify URLs and assets
A migration moves more than post text. Preserve media, metadata, and URL behavior, then verify the generated site before switching traffic.
View full-size diagram (opens in a new tab)

Work through one URL contract

Suppose the old post lives at:

/2020/06/03/example-post/

In your working Hugo site, create content/posts/example-post.md:

---
title: "A migration test"
date: 2020-06-03T09:00:00Z
draft: true
url: /2020/06/03/example-post/
---

This paragraph is a migration marker: amber-post-17.

![A sample chart](/images/migration-demo/chart.svg)

Put an actual test image at static/images/migration-demo/chart.svg. The URL is explicit, so its behavior doesn’t depend on the file’s directory matching your old permalink structure. Hugo’s URL management reference describes url and aliases.

Start a local draft preview from the site root:

hugo server --buildDrafts --bind 127.0.0.1 --port 1313

In another terminal:

curl --fail http://127.0.0.1:1313/2020/06/03/example-post/
curl --fail http://127.0.0.1:1313/images/migration-demo/chart.svg

The first response should contain amber-post-17. The second should return the image. Then inspect the page in a browser: successful HTTP responses alone won’t catch a broken layout or unreadable code sample.

Pause and predict

The new /posts/example-post/ page works, but the old dated URL fails. Is the migration complete?

Need a hint?

Readers and search engines may still use the original address.

Show the reasoning
No. Preserve the old URL or provide a deliberate redirect to the replacement. Test the address people already have, not just the link generated by the new navigation.

Convert content with a known input and output

Choose an exporter that matches the input you have. A WordPress plugin exporter and an XML-to-Markdown converter are different workflows. Inspect their documented invocation and output before applying one across the whole site.

For the specimen, compare heading structure, code fences, image paths, captions, and internal links with the original. Strip obsolete editor markup only after confirming it doesn’t contain meaningful content.

Make a simple migration ledger:

Old item New location Verification
Post URL Explicit front matter URL Expected text at original path
Embedded image Static asset path Image loads and has useful alt text
Internal link Retained URL or redirect Destination exists
Unpublished post Draft content Absent from ordinary build

Verify two builds

A draft preview helps review unfinished content. An ordinary build answers a different question: what would be published?

hugo --destination /tmp/hugo-migration-published

Use a dedicated empty destination for this exercise. Confirm that the test draft is absent from that output. When you deliberately publish the specimen, change its draft flag and rebuild, then verify the intended route.

The Hugo server reference documents preview behavior. If you still need a working starter site, follow Hugo’s quick start before migrating content; a new directory without templates isn’t a complete rendering setup.

Try an edge case

Apply the idea

An old image URL is referenced by other websites. Is copying the image under a new filename enough?

Need a hint?

Those callers don't know your new path.

Show the reasoning
No. Preserve the old asset path or configure a suitable redirect in the serving layer. A correct link inside the new article doesn’t repair external links to the old image URL.

Only expand the conversion after the specimen passes. At cutover, account for edits made since the export and repeat the checks against the actual hosting path. Keep a recovery plan until the migrated content and URLs have been verified.