Article

July 17, 2026 | 10 min read

From Hugo to Astro: How I Rebuilt My Blog and Automated Publishing with Azure Pipelines

How I migrated my blog from Hugo to Astro, rebuilt the design, kept legacy content intact and automated publishing through Azure Pipelines with some help from Codex.

From Hugo to Astro: How I Rebuilt My Blog and Automated Publishing with Azure Pipelines

For years my website was running on Hugo.

Hugo did exactly what I needed for a long time. It was fast, simple and reliable. But over time I started to feel the limits of my existing setup. The theme had aged, parts of the content still carried older patterns from previous platforms, and making structural or visual changes was becoming more work than it should be.

So instead of endlessly patching the old setup, I decided to fully rebuild the site.

The result: my blog moved from Hugo to Astro, got a completely new layout, kept the existing content, and still publishes through Azure Pipelines.

This post is about how I approached that migration, what I rebuilt, what broke along the way, and why I also used Codex to help accelerate parts of the process.


Why I wanted to leave Hugo

This was not really about Hugo being bad.

The bigger issue was that my site had accumulated a lot of historical baggage over the years: old content patterns, legacy shortcodes, image references from earlier setups, and taxonomy structures that were no longer ideal. On top of that, the design no longer matched how I wanted the site to feel.

The content itself was still valuable. The platform around it just needed a reset, a fully new layout, a cleaner structure, better browseability, a more maintainable setup, stronger search and archive support, better SEO foundations, and a publishing flow that stayed just as simple as before.

That made this the right time to rebuild.


Why I chose Astro

I wanted a modern static site setup without turning the blog into a heavy front-end application. I already used Astro for my company website, where it turned out to be a great fit, so it was a very logical choice here too.

What appealed to me most was the static output, the component-based layouts, the flexible structure, and the fast performance. Content rendering stayed easy, and it gave me a clean path to modernize the site visually. In other words, Astro gave me the flexibility I wanted without losing the benefits of a static site.

It felt like the right next step after Hugo.


This was not just a framework migration

The move from Hugo to Astro was only one part of the project.

The real work was in everything around it:

  • preserving existing posts
  • keeping URLs working cleanly
  • migrating old images
  • rebuilding archive pages
  • rebuilding categories and tags
  • restoring search
  • restoring RSS
  • restoring comments and ads in a cleaner way (I later took this further by switching comments from Disqus to Giscus entirely)
  • fixing legacy content behavior

That is where most migrations become messy.

Moving Markdown files is easy. Making sure the site still feels coherent, browseable and publishable afterward is the hard part.


A completely new layout

One thing I cared about from the start was that the new site should not feel like a basic port.

If I was going to rebuild the platform, I wanted the site to look and feel different as well.

So instead of cloning the old structure, I rebuilt the front-end with a more editorial layout:

  • stronger homepage structure
  • cleaner article cards
  • better archive browsing
  • proper category and tag pages
  • improved typography
  • a more modern navigation
  • a better mobile experience
  • cleaner footer and header structure
  • more focused visual hierarchy

That gave the migration a much bigger payoff immediately.

It was not just “same blog, different framework”. It became a noticeably better site.


Preserving content mattered more than rewriting content

An important part of this migration is that I did not manually rewrite every blog post.

That would have taken far too much time and it was not necessary.

Most of the value was already in the existing content. The real challenge was making sure that content continued to work properly in the new setup.

That included things like:

  • old image paths
  • Hugo-specific content patterns
  • legacy caption-like structures
  • older formatting quirks
  • content organization

The goal was not to rewrite history. The goal was to preserve it properly inside a cleaner platform.


Where Codex helped

I also want to be transparent about the fact that I used Codex during this migration.

Not to blindly generate a site, and not to rewrite all content for me, but to help with the repetitive and technical parts of the work.

That included tasks such as:

  • cleaning up framework-specific files
  • migrating old paths and references
  • helping convert legacy content patterns
  • rebuilding structural pages like archive, taxonomy and search
  • troubleshooting styling regressions
  • fixing pipeline and deployment issues
  • helping restore SEO and publishing basics

That saved a lot of time.

The design choices, content choices, structure, migration direction and final decisions were still mine. But Codex was genuinely useful as a force multiplier for the repetitive cleanup and migration work.

In practice, that meant I could focus more on what the site should become, instead of spending all my time doing mechanical conversions by hand.


Rebuilding content browsing properly

One thing I wanted to improve was how easy it is to actually browse the content.

A blog should not only work through the homepage or Google. People should also be able to explore it.

So part of the rebuild was properly restoring and improving:

  • the archive
  • category pages
  • tag pages
  • search
  • RSS

That sounds basic, but it makes a huge difference.

A lot of older sites technically still “contain” useful content, while in practice that content becomes hard to find. I wanted to avoid that.


SEO and AI discoverability were part of the rebuild

I also wanted to make sure the migration did not weaken the technical basics.

So I rebuilt the SEO foundation as part of the move, including:

  • canonical tags
  • sitemap
  • Open Graph metadata
  • fallback descriptions
  • improved page titles
  • RSS feed support
  • robots basics
  • AI-readable basics such as llms.txt

I care about regular search, but also about how content gets picked up by AI systems and summarization tools.

If the site is technically cleaner, better structured and easier to parse, that helps both human visitors and machine readers.


Publishing with Azure Pipelines

I already had a publishing mindset based on static output, so I did not want to replace that with something more complex just because I changed frameworks.

That is why I kept the deployment model simple.

The publishing flow now looks like this:

  1. Build the Astro site
  2. Generate static output
  3. Let Azure Pipelines run the deployment
  4. Publish to Azure Static Web Apps

Here’s a stripped-down version of the actual pipeline, in case it’s useful as a starting point. It checks out the repo, installs Node, runs the Astro build, and deploys the dist output straight to Azure Static Web Apps. The deployment token is pulled from a variable group rather than hardcoded, so nothing sensitive lives in the YAML itself:

name: 20260716.$(Rev:r)

pr:
  branches:
    include:
      - main
trigger:
  branches:
    include:
      - main

jobs:
- job: build_and_deploy_job
  displayName: Build and Deploy Job
  condition: or(eq(variables['Build.Reason'], 'Manual'),or(eq(variables['Build.Reason'], 'PullRequest'),eq(variables['Build.Reason'], 'IndividualCI')))
  pool:
    vmImage: ubuntu-latest
  variables:
  - group: Azure-Static-Web-Apps-variable-group
  steps:
  - checkout: self
    submodules: true
  - task: UseNode@1
    inputs:
      version: "22.x"
    displayName: "Use Node.js"
  - script: |
      node -v
      npm -v
      npm ci
      npm run build
    displayName: "Build Astro site"
  - task: AzureStaticWebApp@0
    inputs:
      azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN)
      app_location: "dist" # App artifact path
      api_location: "" # Api source code path - optional
      output_location: "" # Built app content directory - optional
      skip_app_build: true

The pipeline only triggers on main, so pull requests get validated but nothing deploys until it’s merged. skip_app_build: true matters here, it tells the Static Web Apps task not to run its own build step, since the Astro build already produced the dist folder in the previous step.

That was important to me.

I wanted the rebuild to modernize the site, not complicate the operational side of it.

In the end, Astro fit this model very well.


What broke along the way

Of course, no migration is ever fully smooth.

Some of the issues I ran into included:

  • search regressions
  • taxonomy conflicts
  • Azure pipeline configuration issues
  • Static Web App routing quirks
  • responsive design fixes
  • old content patterns that still expected Hugo-like behavior
  • image path cleanup
  • footer/header refinements after the initial rebuild

This is normal.

A migration like this is not a single technical action. It is a chain of rebuild, cleanup, verification and polish.

That is also why I think these projects should be treated as real product work, not just framework work.


What is better now

Now that the migration is done, the site is in a much better place.

There’s a fully new design, a more maintainable structure, and cleaner navigation. Category and tag support is better, search and RSS are fully restored, and the SEO foundations are stronger than before. Static publishing through Azure Pipelines continued without disruption, the mobile experience is better, and the whole setup is easier to keep evolving.

Most importantly, the site no longer feels like something I am working around.

It feels like something I can build on again.


Lessons learned

If I would do this again, I would follow the same principles:

  • preserve content first
  • preserve URLs where possible
  • modernize structure second
  • polish the front-end third
  • only remove legacy patterns once you are sure they are no longer needed

The biggest trap in a migration is focusing too much on the framework and not enough on the content, URLs and reading experience.

Readers do not care whether the site runs on Hugo or Astro. They care whether the site is fast, usable, readable and better than it was before.

That should be the real benchmark.


Last note

Moving from Hugo to Astro ended up being much more than a framework change.

It became an opportunity to modernize the entire site:

  • design
  • structure
  • search
  • SEO
  • publishing
  • maintainability

And because I used Codex to help with the repetitive technical parts, I was able to move much faster without manually reworking every single piece of content.

That combination worked well for me: human direction, human decisions, and AI assistance where it actually adds value.

If your current static site still works but increasingly feels hard to evolve, a migration like this can absolutely be worth it, as long as you treat it as a full rebuild of the experience and not just a change of framework.

Ads appear here only after advertising consent.