Comment by dijit

7 days ago

I made the jump to Hugo too (from a managed service: svbtle) a long time ago, but I'll be really honest...

I regret it.

I decided to use an off-the-shelf theme, but it didn't quite meet the needs and I forked it; as it so happens Hugo breaks userland relatively often and a complex theme like the one I have requires a lot of maintenance. Like.. a lot.

Now I can't really justify the time investment of fixing it so I just don't post anymore, the site won't even compile. In theory I could use an old version of Hugo, but I have no idea when it broke, so how far do I go back?

So, advice: submit the binary you used to generate the site to source control. I know git isn't the best at binary files, but I promise you'll thank me at some point.

I’ve slowly grown to realize there’s some software you just don’t need to update. A static site generator (almost certainly) won’t have security issues as long as you control the input and the output is just a bunch of static files.

Unless the new version of the software includes some feature I need, I can be totally fine just running an old version forever. I could just write down the version of the SSG my site builds with (or commit it to source control) and move on with my life. It’ll work as long as operating systems and CPU architectures/whatever don’t change too much (and in the worst case scenario, I’m sure the tech exists to emulate whatever conditions it needs to run) Some software is already ‘finished’ and there’s no need to update it, ever.

  • Is there any static site generator where you specify the version you use, and the launcher will simply run the old binary that you want?

    Like most build systems work, for example when you set a "rust-version" in Cargo.toml and only bump it when you explicitely want to. This way it will still use the older version on a fresh checkout.

    • Just wrap it in a Nix flake and define a devshell. The entire config won’t exceed more than ~10 lines of Nix.

      Once setup, all you need to do is:

          $ nix develop —-command hugo regenerate
          $ # version is pinned by flake.lock
      

      The beauty of this approach is that it extends to almost any CLI tool you can think of :)

      1 reply →

    • > Is there any static site generator where you specify the version you use, and the launcher will simply run the old binary that you want?

      For Hugo, there is Hugo Version Manager (hvm)[0], a project maintained by Hugo contributor Joe Mooring. While the way it works isn't precisely what you described, it may come close enough.

      [0]: https://github.com/jmooring/hvm

      2 replies →

    • I use `mise` to manage all my tool versions[0] and committing the version file to the repo is sufficient for later use. https://mise.jdx.dev/

      0: not all, I use cargo to manage the rust toolchain

How about specifying a version in the CI config? [0]

Also, you know that you can do a binary search for the version that works for you? 0.154.0, 0.77.0, 0.115.0 ... (had to do it once myself)

[0]: https://github.com/oslc-op/website/blob/9b63c72dbb28c2d3733c...

  • This is probably the smarter way actually.

    Alternatively there's apparently some nix flakes that have been developed.

    So, there's options.

    I just recommend pinning your version and being intentional about upgrades.

    • > This is probably the smarter way actually.

      Oh definitely. How can you suggest adding a binary to a git repository? It's a bad idea on many levels: it bloats the repository by several orders of magnitude, and it locks you to the chosen architecture and OS. Nope, nope, nope.

      1 reply →

  • Second this. Once I setup GitHub actions with Hugo (there’s one readily available), I rarely build the blog locally anymore. New article drafts become GH pull requests, and once ready they get merged and published. This also works on mobile well enough.

If you use an off-the-shelf binary for any tool, you can put the binary in `${project}/bin/`, add it to `.gitignore`, document the download URL in `README.md` or an install script, and commit the checksum in a project-wide `SHA256SUMS` file (or `B3SUMS`, etc.). It's like a lo-fi version of Git LFS.

I "solved" this issue by using a custom Docker image, both for writing/serving content locally, and for the CI.

So I have a fixed Hugo version that I know works.

And when I mean "solved", I actually never had the issue because, since I have no reason to upgrade Hugo, I never had to change my Docker image and never had the opportunity to risk breaking my theme.

I recently broke my Hugo blog theme when updating and had to migrate to a whole new theme, it was a pain. From now on I probably won't update it

  • That should definitely improve.

    Right now, you are pretty much locked into the theme (and it's version) when you set up your website for the first time.

I had a similar issue, but with Jekyll. I had a customized theme and some update along the way broke everything. So, I very much agree with a sibling comment about not needing to update static site generators and it’s not just a Hugo thing. Sadly, my site was also being hosted/generated by GitHub, so I had no real choice in the update matter. (I’m not sure if pinning would have helped.)

I moved to a AI maintained custom site generator and it’s ideal for my uses. I have full control over everything and nothing breaks me.

I had the same issue and I'm currently thinking whether it's easier to just Vibe Engineer my own static site generator with the exact features I need vs fighting with the hugo theme system.

My needs for a site are pretty simple, so I might just go with the custom-built one to be honest.

If it breaks, I can just go look in the mirror for the culprit =)

  • EDIT: Just made my own. Claude + Opus and about 3-4 prompts.

    Looking at the comments here a common pain (that I share) is config and code drift, or just losing your config file and being unable to publish a new version without re-doing everything.

    I made a version where everything, including the HTML templates and CSS, is built in to a single static Go executable, no configuration files, everything is hard-coded.

    This way as long as I have the specific executable version and the source markdown files, I can deterministically replicate my blog output structure.

    The source is a directory in my Obsidian vault and the setup supports Obsidian-style front-matter

> In theory I could use an old version of Hugo, but I have no idea when it broke, so how far do I go back?

Had the same problem. Binary search is the latest trick people use.

For SSG there's not much point in upgrading if everything works, and planned migration beats the churn in this case.

You can just print a Hugo version in a HTML comment to track it in git.

I have the same problem with Jekyll. I fixed my website for the Jekyll version I installed when I got this machine (in 2021). I dread the moment when I get a new computer and have to either try to install this particular version of Jekyll or to fix my website again.

I just assumed static website generators would be stable but well, there's always something that breaks. Terrible user experience for someone who just wants to use the generator to generate a website vs. to tinker with it as a hobby.

I'm in the process of porting my website to PHP ... but that project hasn't gone anywhere because currently everything works ;)

  • In retrospect, Jekyll has been relatively stable recently. The last stable release was in January 2025, v4.4.1[1].

    I've been using 4.3 to 4.4 without much issues, granted the sites I generate are simple.

    [1]: https://jekyllrb.com/news/

> I decided to use an off-the-shelf theme, but it didn't quite meet the needs and I forked it; as it so happens Hugo breaks userland relatively often and a complex theme like the one I have requires a lot of maintenance. Like.. a lot.

> Now I can't really justify the time investment of fixing it so I just don't post anymore, the site won't even compile. In theory I could use an old version of Hugo, but I have no idea when it broke, so how far do I go back?

I've had the same issues as you, and yes, I agree that pinning a version is very important for Hugo.

It's more useful for once-and-done throwaway sites that need some form of structure that a static site generator can provide.

> So, advice: submit the binary you used to generate the site to source control. I know git isn't the best at binary files, but I promise you'll thank me at some point.

No need for the entire binary.

Just put `go run github.com/gohugoio/hugo@vX.Y.Z "$@"` into a `hugo.sh` script or similar that's in source control, and then run that script instead of the Hugo binary.

You'll need Go installed, but it's incredibly backwards compatible, so updating to newer Go versions is very unlikely to break running the old Hugo version.

I've been burned by this a few times and now I have the Hugo binary in source control. I had to dig through the releases a little bit to find the version that didn't break everything.

  • Yeah. That's one flip side.

    Hugo-papermod, the most famous Hugo theme, doesn't support the latest 10 releases of Hugo.

    So, everyone using it is locked into using an old version (e.g. via Docker).

At least it’s practical to identify a specific version to use, and you can be reasonably confident it will work indefinitely. I remember that with the Hyde iteration of my site, somewhere along the way Hyde became impossible to install, and I was stuck with an existing installation, or a lot of effort to put it back together manually. Python packaging has improved a lot since then, so that I doubt that problem would apply on any new project, but it’s still far more plausible than in a language like Go or Rust.

I maintained a personal fork of Zola for my site (and a couple of others), and am content to just identify the Git repository and revision that’s used.

Zola updates broke my site a few times, quite apart from my patches not cleanly rebasing. I kept on the treadmill for a while, initially because of a couple of new features I did want, but then decided it wasn’t necessary. You don’t need to run the latest version; old is fine.

—⁂—

One piece of advice I would give for people updating their SSG: build your site with the old and new versions of the SSG, and diff the directories, to avoid regressions.

If there are dynamic values, normalise both builds before diffing: for example, if you have timestamp-based cachebusting, zero all such timestamps with something like `sed -i 's/\?t=[0-9]+/?t=0/' **/*`. Otherwise regressions may be masked.

I caught breakages a couple of times this way. Once was due to Zola changing how shortcodes or Markdown worked, which I otherwise might not have noticed. (Frankly, Markdown is horrible for things like this, and Zola’s shortcodes badly-designed; but really it’s mostly Markdown’s fault.)

Sorry to hear it. Always sucks to not be able to tweak your own site.

I’ve had amazing success debugging compile errors with Claude Code.

Perhaps a coding agent could help you get it going again?

  • A pretty light-grey comment as I came across it. Maybe I’m missing something odious about it? People downvote this, but as a VERY skeptical AI skeptic, it’s exactly the sort of use case that makes sense to me:

    A) Low-stakes application with

    B) nearly no attack surface that

    C) you don’t use consistently enough to keep in your head, but

    D) is simple enough for an experienced software developer to do a quick sanity check on and run it to see if it works.

    Hell, do it in a sandbox if you feel better about it.

    If it was a Django/Node/rails/Laravel/…Phoenix… (sorry, I’ve been out of my 12+ years web dev career a short 4 years and suddenly realized I can only remember like 4 server-side frameworks/environments now) application, something that would run on other people’s devices, or really anything else that produces an executable output, then yeah fuck that vibe coding bullshit. But unless you’ve got that thing spitting out an SPA for you, then I say go for it.

  • Yeah I feel like Claude Code is basically tailor made for a use-case like this. Where:

    * I have forked some public repository that has kept up with upstream (IE; lots of example code to draw from)

    * Upstream is publishing documentation on what's changing

    * The errors are somewhat google-able

    * Can be done in a VM and thrown away

    * Limited attack surface anyway.

    I think you're downvoted because the comment comes across as glib and handwavy (or not moving the discussion forward.. maybe?), and if it was a year ago I would probably argue against it.. but I think Claude Code can definitely help with this.

    It just didn't exist as it does in 2023~ or whenever it was that I originally started having issues.

    ---

    That said: it shouldn't be necessary. As others in this thread have articulated (well, imo) sometimes software is "done" and Hugo could be "done" software, except it's not; so the onus is on the operator to pin their definition of "done" version.. which is not what you'd expect.

    • > handwavy

      Yep. I missed the mark.

      OP seemed down and out about their blog being broken. So I was trying to put the idea across as not something to be afraid of.

      I should’ve just said it - LLMs are perfect for this use case.

      1 reply →

> In theory I could use an old version of Hugo, but I have no idea when it broke, so how far do I go back?

Pretty sure the version of Hugo used to generate a site is included in metadata in the generated output.

If you have a copy of the site from when it last worked, then assuming my above memory is correct you should be able to get the exact version number from that. :)

What kind of issues? I use my own private theme called Brahma which I wrote from scratch. I keep it simple and has been since 2019. I have barely had any issues.

Given, mine is not sophisticated at all and simple by design. But curious what kind of issues pops up.

> advice: submit the binary you used to generate the site to source control.

Or use HVM and submit the .hvm file (which is just a text file with the Hugo version that you use)

Run Hugo in Docker; in that instance, rolling forward/back is as easy as changing the tag in your Docker image.

  • it's a Go programmer, so it's statically linked by default.

    No need for docker.

    • It's useful if you want more control over how directories are mounted. I use this to hot-swap themes, for example.

Why not go back to the version that your last post was published at, and stick with it?

  • I can try that version, but it's entirely possible (and even: likely) that I was already using an old version of Hugo then; whatever was installed by my package manager - assuming I updated my machine somewhat recently.

    If I used MacOS then Hugo was probably very old, since I often forget to update brew packages and end up running very old software.

    But, that's what I thought to do first also.

    In the end, it becomes not worth the hassle, and spending time fixing it means that whatever I was going to write gets pushed out of my head, and it's very difficult to even bother.

    I'll probably go back to Svbtle.

I'm on your side.

Nobody can point to a reason why it's a good idea for a site with any interactivity now.

All the supporters here are all the same: "I had to do a whole bunch of mental gymnastics and compromises to get <basic server side site feature> but it's worth it!" But they don't say why it was worth it, beyond "it's easy now <after lots of work costs sunk>".

When you try get to why they did it in the first place, it's universally some variation on "I got fed up with <some large server side package> so took the nuclear SSG route <and then had to eventually rewrite or get someone else's servers involved again>"

Part of this is a me problem: a personal website should be owned by the person, IMO. A lot of people are fine to let other people own parts of their personal websites, and SSGs encourage that. What even is a personal website if it's a theme that looks like someone else's, hosted and owned on someone else's server - why not just use Facebook at that point?!

  • I was nodding along until your last paragraph - SSGs encourage letting other people own parts of your personal site, really? Sure, people bolt on Disqus or something, but otherwise I am not sure I follow the argument. Isn't part of the appeal of SSGs that all you have is a bunch of html/css/js that you can drop on any server anywhere (even a solar-powered RPi can serve a lot of requests[1])?

    1: https://www.vice.com/en/article/this-solar-powered-low-tech-...

    • > Isn't part of the appeal of SSGs that all you have is a bunch of html/css/js that you can drop on any server anywhere (even a solar-powered RPi can serve a lot of requests[1])?

      This is the part I'm struggling with. That's the view I held from 2016 - 2024. Practically though, it's only true if you want a leaflet website with 0 interactivity.

      If you want _any_ interactivity at all (like, _any_ written data of any kind, even server or visitor logs) then you need a server or a 3rd party.

      This means for 99% of personal websites with an SSG, you need a real server or a 3rd party service.

      When SSGs first came around (2010 - 2015) compute was getting expensive, server sides were getting big and complex, bot traffic solutions were lame, and all the big tech companies started offering free static hosting because it was an easy free thing to offer.

      Compare this to now, 2026, it's apparently nothing special to handle hackernews front page on free or cheap compute. Things like Deno, Bun, even Go and Python make writing quick, small, modern server sides so much quicker, easier and safer. Cloudflare and or crowdsec can cover 99% of bot and traffic issues. It's possible to get multiple free multiple GB compute instances now.

      I didn't mean to imply there's some sinister plot of people maliciously encouraging people to use SSGs to steal their stuff, but that's the reality that modern personal webdev has sleepwalked into. SSGs were first sold to make things better performing and easier than things were at the time. Pretty much any "server anywhere" you own now will be able to run a handwritten server doing SSR markdown -> HTML now.

      So why force yourself to have to start entertaining ideas like making your visitors download multiple megabyte client side index files to implement search, or embedded iframes and massive JS external libraries for things like comment sections? Easier looking SSG patterns like that typically break all the stuff required to keep the web open and equal, like screen readers, low bandwidth connections and privacy. (Obviously SSR doesn't implicity solve these, but many of these things were originally conceived with SSR in mind and so are naturally more compatible).

      Ask anyone who's been in and out of web dev for more than 15 years to really critically think about SSGs in depth, and I think they'll conclude they offer a complete solution for maybe 1% of websites, but seem to be recommended in 99% of places as the only worthy way to do websites now. But when you pick it apart and try it, you end up in Jeff's position: statically rendered pages (the easy bit) and a TODO with a list of compromising options for basic interactivity. In 5 years time, he'll have complex SSG pipelines that's running almost 24/7, or a complex mesh of dependencies on external services that are constantly changing or trying to start charging him more to deal with his own creations.

      I really hope I'm wrong.

      1 reply →

It may be worth considering whether you need a native binary (and the ability to run it) for the job at all. A static site generator doesn't need to do anything that browsers from the last 10 years can't do; a static site generator is fundamentally a classic batch processing job that takes a collection of (mostly plain text) files as input, processes it, and then outputs something else (in this case, a collection of post-processed content for the site).

If you encode the transformations that your desired SSG should perform by writing the processing rules as plain text source code that a browser is capable of executing (i.e., an "HTML tool" or something adjacent[1][2]), then you can just publish this "static site generator" itself as yet another page on your static site.

To spell it out: running the static site generator to create a new post* doesn't need to involve anything more than hitting /new.html (or whatever) on the live site, clicking the button for the type=file input on that page, using the browser file picker to open the directory where the source to your static site lives, and then saving the resulting ZIP somewhere so the contents can be copied to whatever host you're using.

1. <https://simonwillison.net/2025/Dec/10/html-tools/>

2. <https://crussell.ichi.city/pager.app.htm>

* in fact, there's nothing stopping you from, say, putting a textarea on that page and typing out your post right there, before the new build