Skip to content

Let hugo build the 404 page directly (#862)#1083

Open
dduugg wants to merge 1 commit into
shift-org:mainfrom
dduugg:issue-862-404-cleanup
Open

Let hugo build the 404 page directly (#862)#1083
dduugg wants to merge 1 commit into
shift-org:mainfrom
dduugg:issue-862-404-cleanup

Conversation

@dduugg

@dduugg dduugg commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #862.

The build has a postdeploy step that copies the 404 page into place after every deploy:

"postdeploy": "cp site/public/404/index.html site/public/404.html",

The issue asks whether "we could do this better/easier/automatically these days." We can: the copy is unnecessary once hugo is told where to put the page.

Why the copy existed

Netlify serves /404.html for any unmatched URL. Hugo emits a root 404.html on its own, but only when there is no content/404.md. Because this site has one, hugo treats it as an ordinary page, routes it to /404/index.html, and emits no root 404.html. The cp existed to paper over that gap.

The change

Point the page at /404.html with url front matter, and hugo writes it exactly where netlify wants it. The postdeploy copy and the accompanying netlify.toml note are then dead, so both are removed.

url: '/404.html'

Also in this PR:

  • Deleted the theme's layouts/404.html. It has never rendered, for the same shadowing reason, so its header comment ("this file gets overwritten by netlify.toml with 404.md") describes a mechanism that does not exist. content/404.md is the real 404 page and is what site/static/admin/config.yml exposes to the CMS for editing. Removing the template leaves exactly one 404 page.
  • Excluded the page from the sitemap (sitemap: disable: true). A "page not found" page has no business being advertised for indexing.
  • Updated the two stale pedalpalooza links. They pointed at /pedalpalooza-calendar/ and /pages/pedalpalooza, neither of which is a real page anymore (each survives only as a 301 to its bike-summer equivalent). Pointed them straight at the targets and updated the visible link text to "Bike Summer".

Verification

Built with the same command netlify runs for production (npm run deploy calls hugo -s site), with the postdeploy hook removed, and confirmed:

  • site/public/404.html lands directly in the publish directory (publish = "site/public/").
  • The stray /404/ directory is no longer generated.
  • The sitemap has zero 404 references.
  • /404.html still exists, which matters because _default/list.html hard-redirects there (<meta http-equiv="refresh" content="0; url=/404.html" />).

Diffing the generated page against the previously shipped one shows only the intended link changes and nothing structural. The theme template was confirmed dead by comparing 404 output with and without it (byte-identical); note that the wider hugo build is nondeterministic (whitespace-only churn in a couple of unrelated files between runs), so the comparison was scoped to the 404 output specifically.

No backend or frontend code is touched, so there is nothing for the app test suite to cover.

Dependency on #1080

This interacts with #1080 (add a robots.txt). That PR includes Disallow: /404/, which matches the old /404/index.html path. Since this PR moves the page to /404.html, #1080 has been updated to Disallow: /404.html so the rule still matches after both land. Whichever merges second, the robots.txt rule is already correct for the final state.

`postdeploy` copied site/public/404/index.html over to
site/public/404.html after every deploy, because netlify serves
/404.html for unmatched urls and hugo was not producing it.

Hugo skips its native root 404.html whenever content/404.md
exists: the content page claims the route and renders to
/404/index.html instead. Point the page at /404.html with `url`
front matter and hugo writes it where netlify wants it, so the
copy is no longer needed. Drop it, and the netlify.toml note.

Also drop the theme's layouts/404.html. It has never rendered,
for the same reason, so its header comment describes a mechanism
that does not exist. content/404.md is the real 404 page, and is
what static/admin/config.yml offers up for editing.

While here: exclude the page from the sitemap, and point its two
pedalpalooza links straight at their bike-summer targets rather
than through a 301.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

clean up 404 page

1 participant