I’ve had this blog around (in one form or another) since 2010.
Like a lot of dev blogs, it collected years of “here’s the fix”, “here’s the link”, and “future-me will thank me”.
And then… life happens. The platform changes, domains move, images disappear, and the archive slowly gets harder to maintain.
So I rebuilt it.
This time, it wasn’t “just a redesign”.
I was migrating from a BlogEngine.NET file-based setup to Markdown + Hugo. Real work.
The stack is intentionally boring: Hugo for content and Azure Static Web Apps for hosting.
The hard part wasn’t picking tools. It was keeping what matters intact.
Here were my rules
- Old links should keep working.
- English and French should stay first-class.
- Publishing should feel like development: edit → commit → PR → merge.
That last one is why the whole thing lives on GitHub. It’s not glamorous, but it’s the most robust workflow I know (and I use it every day).
Inventory (aka: what I was actually migrating)
- Posts across multiple tech eras
- A mix of quick tips and longer articles
- Bilingual content
- A pile of legacy URLs (including old
.aspxroutes)
Migrating to Markdown is easy. Migrating expectations is not.
The one thing I refused to break: URLs
I don’t want to be the person who breaks a link someone bookmarked in 2011.
So I kept the permalink shape consistent. In my Hugo config, that looks like:
[permalinks]
[permalinks.page]
post = "/:year/:month/:slug/"
And for the really old routes, Hugo aliases do the job. Example from one of the 2010 posts:
aliases:
- /post/2010/03/24/ASPNet-Path.aspx
That’s not exciting work. But it’s the kind of detail that makes an archive trustworthy.
Bilingual content (without turning it into a maintenance project)
I’ve kept EN/FR posts for years. It’s extra work, but it’s worth it.
During the migration, I also found a few posts that only existed in one language.
I used AI to help translate those missing versions so the archive stayed consistent (and so I didn’t turn this whole thing into a multi-month translation marathon).
What really helped was adopting page bundles for newer posts: one folder per post, with index.en.md and (optionally) index.fr.md.
Images live beside the post that uses them. No more “where did I put that PNG in 2013?”.
Hugo’s language setup is straightforward. In my config:
[Languages]
[Languages.fr]
LanguageCode = "fr"
weight = 1
[Languages.en]
LanguageCode = "en"
weight = 2
Set French as DefaultContentLanguage, weight determines the menu order, and Hugo handles the routing.
When both index.en.md and index.fr.md exist, they’re treated as the same post in different languages, not separate posts.
Hugo: boring is good
I’ve used enough blogging engines to learn a pattern: if publishing has friction, you stop publishing.
Hugo keeps it simple: Markdown in, static files out.
One note from my setup: I left Git metadata off (enableGitInfo). It caused problems in the Azure build container for me, and I’d rather have reliable deploys than a fancy “last updated” stamp.
I did keep SEO-friendly touches: enableRobotsTXT = true generates a robots.txt, and I tuned image caching ([caches.images] for processed images) so rebuilds stay fast. It’s the kind of unglamorous config that pays off when your site gets crawled or when you’re iterating.
Azure Static Web Apps: simple hosting that stays out of the way
I wanted previews on PRs and automatic deploys on merge, without babysitting a server.
Another nice bonus: Azure Static Web Apps can build Hugo sites out of the box. That meant fewer custom steps and less “CI archaeology” later.
The workflow is basically: check out the repo → build with Hugo → publish the public folder. That’s it.
Here’s the relevant shape of the GitHub Action:
- uses: actions/checkout@v6
with:
submodules: true
- uses: Azure/static-web-apps-deploy@v1
with:
app_location: "/"
output_location: "public"
env:
HUGO_VERSION: 0.147.2
The submodules: true is important: it pulls in the theme (beautifulhugo) which lives in Git as a submodule, not checked into the main repo. Pinning HUGO_VERSION looks like a tiny detail, but it prevents the classic “it worked yesterday” surprise when the build image changes.
The work was mostly small fixes
It was a lot of:
- Fixing a few image paths
- Normalizing front matter
- Updating a couple internal links
- Deciding what stays as a historical artifact vs. what deserves a refresh
Not hard. Just steady.
If you’re thinking about rebuilding an old blog, start with these:
- Decide your permalink shape first
- Keep your legacy URLs alive (aliases/redirects)
- Keep assets close to posts (page bundles help a lot)
- Automate deploys so publishing stays easy
Happy deploys (and no broken links).