Caching Broken when renaming _index.md files

I started using Hugo just tonight. I’ve got a heavy background in software development, systems administration for both RHEL and Windows, I run my own homelab via three Dell servers running Proxmox. I had written commercial software a few decades ago on my own, and I supported it, and I’ve seen strange things with that old software, so I’m not a stranger to weird oddities. I tend to find them rather quickly unintentionally even today, both with my own code, and with others.

That said, I can’t quite put my finger on the behaviour I’m seeing with Hugo and running the server in memory mode.

I’m running the server out of a shell script under WSL with Debian as the OS:

#!/bin/bash
hugo server --forceSyncStatic -M --gc --disableFastRender --noHTTPCache

The gc probably is a noop here, sure, fine, ok. I was swapping between disk and ram modes and that just stuck.

Here’s the version reported when I run:

$ hugo version
hugo v0.151.0-c70ab27ceb841fc9404eab5d2c985ff7595034b7+extended linux/amd64 BuildDate=2025-10-02T13:30:36Z VendorInfo=gohugoio

So here’s my problem.

The short of it is that Hugo is seeing work being done against a file, writing the generated code to a cache, but forgetting it after a reload. I’d expect that the entire code base for all files would be done on engine start up, but there seems to be something missing in the process. I’d also expect that Hugo would look at EVERY page, parent or child, list or page, leaf or branch.

I’m attempting to figure out how to write my own breadcrumb for certain pages. The intent is to list off ALL the pages for the particular laser focused subject I’m writing about. I’m manually maintaining them in a shortcodes file.

$ find . -type f | grep bread
./layouts/shortcodes/breadcrumbs.html

In each index file I have a {{<breadcrumbs>}} entry right after the front matter for consistency. This renders to the pages I’ve listed this on (I’ll rename later to something more specific when/if I get more accustomed to Hugo).

This is the file structure I’m running with:

$ find . -type f | grep homelab | sort
./content/homelab/dhcpdns/01-tooling/index.md
./content/homelab/dhcpdns/02-phpipam/index.md
./content/homelab/dhcpdns/03-walkthrough/index.md
./content/homelab/dhcpdns/index.md
./content/homelab/_index.md
./content/homelab/proxmox/index.md

This is what the list shows

$ hugo list all | grep homelab
WARN  module with path "terminal" is imported for the same version "" more than once
content/homelab/_index.md,,,2025-10-05T23:00:00Z,0001-01-01T00:00:00Z,2025-10-05T23:00:00Z,false,/homelab/,section,homelab
content/homelab/dhcpdns/index.md,,phpIPAM - My IP Management System,2025-10-05T23:00:00Z,0001-01-01T00:00:00Z,2025-10-05T23:00:00Z,false,/homelab/dhcpdns/,page,homelab
content/homelab/proxmox/index.md,,Proxmox Hardware Config,2023-10-05T00:00:00Z,0001-01-01T00:00:00Z,2023-10-05T00:00:00Z,false,/homelab/proxmox/,page,homelab

I understand that index.md and _index.md do different things in Hugo world. I understand the behaviour I’m seeing (when its working), I don’t understand the terminology being used.

When I start the server with the file and directory structure you see above, when I go to http://localhost:1313/homelab/ I see both my Proxmox Hardware Config and the phpIPAM directory. I can go into phpIPAM, and I see the content I’ve written. However, when I click on the breadcrumb links, I run into 404s.

This is probably because of a mix up with the index versus _index files. That’s fine, that’s not what I’m here to report on. I’ll figure that jazz out later with more dents in the desk, I’m sure.

What I am here to report on is how the server is caching its content internally and not cleaning up after itself. It’s doing something very wrong and what it’s showing me is NOT representative of what my markdown is being written out as.

While the server is still running, I go into the deepest subdirectories (The 01, 02, and 03) and rename the index.md to _index.md. With every rename, I see the server say it’s rebuilding the file. Cool.

Serving pages from memory
Web Server is available at //localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

Change detected, rebuilding site (#1).
2025-10-05 23:49:17.908 -0400
Source changed /homelab/dhcpdns/01-tooling/index.md
Source changed /homelab/dhcpdns/01-tooling/_index.md
Web Server is available at //localhost:1313/ (bind address 127.0.0.1)
Total in 11 ms

Change detected, rebuilding site (#2).
2025-10-05 23:49:26.408 -0400
Source changed /homelab/dhcpdns/02-phpipam/index.md
Source changed /homelab/dhcpdns/02-phpipam/_index.md
Web Server is available at //localhost:1313/ (bind address 127.0.0.1)
Total in 7 ms

Change detected, rebuilding site (#3).
2025-10-05 23:49:32.408 -0400
Source changed /homelab/dhcpdns/03-walkthrough/index.md
Source changed /homelab/dhcpdns/03-walkthrough/_index.md
Web Server is available at //localhost:1313/ (bind address 127.0.0.1)
Total in 6 ms

With the renames in place, I have this file structure now:

$ find . -type f | grep homelab | sort
./content/homelab/dhcpdns/01-tooling/_index.md
./content/homelab/dhcpdns/02-phpipam/_index.md
./content/homelab/dhcpdns/03-walkthrough/_index.md
./content/homelab/dhcpdns/index.md
./content/homelab/_index.md
./content/homelab/proxmox/index.md

When I go to the web page, go back to the homelab landing page, then go into the phpIPAM page, my breadcrumbs work. Which that in itself is fantastic.

However, things start to go off the rails right about now.

$ hugo list all | grep homelab
WARN  module with path "terminal" is imported for the same version "" more than once
content/homelab/_index.md,,,2025-10-05T23:00:00Z,0001-01-01T00:00:00Z,2025-10-05T23:00:00Z,false,/homelab/,section,homelab
content/homelab/dhcpdns/index.md,,phpIPAM - My IP Management System,2025-10-05T23:00:00Z,0001-01-01T00:00:00Z,2025-10-05T23:00:00Z,false,/homelab/dhcpdns/,page,homelab
content/homelab/proxmox/index.md,,Proxmox Hardware Config,2023-10-05T00:00:00Z,0001-01-01T00:00:00Z,2023-10-05T00:00:00Z,false,/homelab/proxmox/,page,homelab

I don’t see a difference in line counts here between this and the previous post of showing the list. Strange that. But where things are ACTUALLY broken, is if I stop the server, then immediately restart it, and I refresh on the 03-Walthrough page, I immediately get a 404.

So from just watching what’s happening, Hugo server is seeing that I’m “doing work” on a file, and it’s going and doing its work to render the page, update it’s stuff, and whatever else it needs to do. But between restarts, it loses the changes to what the index and _index file renames did, which isn’t valid work. It probably keeps those files around when writing to disk, but that just means that the public folder doesn’t have the exact content my markdowns are supposed to be rendered out as.

My concern is for when I go OUT of memory storage mode and switch back to disk mode, if I nuke the public folder, and let Hugo rebuild, I’m not going to get the correct answer post build. (Even if my filename convention is wrong regarding index – I get it – I’ll work through that and restructure if needed)

So what’s the fix here? What am I doing wrong, if anything? Bug? Crazy me? Something that’s been discussed previously but decided to not work on?

I appreciate the work, as it saves me from coding something like this myself ground up (And I can do that, it’s just I’d rather work on my homelab stuff than things like this right now).

Your file structure would be a lot easier to understand if you posted the output of tree. And in general, your chances to receive accurate and timely help here are better when you post a link to a GitHub repo with your Hugo project (all of it).

Also, changing index.md to _index.md will change its content is rendered: section or list template for _index.md, page or single template for index.md.

The plan IS to put it up on the repo, but I don’t have that done yet as I was working through writing out the docs before first commit. I’ll look at putting it up in a branch today.

$ tree
.
├── homelab
│ ├── dhcpdns
│ │ ├── 01-tooling
│ │ │ └── _index.md
│ │ ├── 02-phpipam
│ │ │ └── _index.md
│ │ ├── 03-walkthrough
│ │ │ └── _index.md
│ │ └── index.md
│ ├── _index.md
│ └── proxmox
│ └── index.md
├── includes
├── _index.md
├── posts
└── retro
├── 2024
├── 2025
│ ├── 486dx-80
│ │ └── index.md
│ └── Pentium2
│ └── index.md
└── index.md

Whenever you use _index.md, you’re declaring a “section”. Which will be rendered with a section or a list template. Depending on what that template does, the page you see may or may not be what you expect.

Similarly with an index.md, which will be rendered by a page or a single template. The HTML generated by section and page templates will vary wildly.

Now, you must not have an index.md in a directory containing subdirectories in turn containing MD files that you want to render. The details are explained in the documentation’s section on page bundles.

Having an _index.md in a directory that does not contain anything (ie no subdirectories) does not make a lot of sense, I think.

regarding the dev server comments:

rename/move of a file may not be cought up successfully cause it comes from outside and the server does not know if it’s new or the same file renamed - also the build doe not delete stuff in public, so anything generated before will still be there.

index and _index are very special resulting in a major change in the internal document tree, so it’s like an change in the architecture of the site not only a page content update. Those kind of changes may/will need a restart of the server.