← Back to blog
From the blogGuides

I finally moved this website from Hugo to Astro

· Updated 24 October 2026
Illustrated old blog and portfolio windows joining into one new site

In my first post, I wrote a whole walkthrough for getting a Hugo site online. I even included the terminal commands because they made the process look cool. Three years later I have moved this site to Astro, so I suppose I owe Hugo a proper follow-up.

Hugo did its job. The problem was that my blog lived on Hugo and Netlify while the portfolio I built later lived on React and Vercel. Whenever I wanted to change something about my online home, I had to remember which project it belonged to. In that 2024 post I said I wanted to amalgamate everything under one roof. It took me a while, but here we are.

I also wanted the blog to feel like part of the same site as my projects. The writing matters as much to me as the things I build, even if my posting frequency has historically suggested otherwise.

Why Astro?

I still like writing posts in Markdown and serving a static website. Astro lets me do that while giving me components for the bits that need more attention. The pages are built as HTML, and I can keep the interactive parts, including the cube on the landing page, where they belong. I did not need to keep an entire separate React portfolio just to have a bit of Three.js fun.

The site now has one codebase for the homepage, About, projects and blog. Tailwind handles the styling, Three.js runs the cube and Astro’s content collections keep the posts and projects organised. There is no CMS or database behind the blog. I write a Markdown file, build the site and publish it. That part is reassuringly familiar.

How I would set it up today

My Hugo post started at Step 0, so let’s keep the tradition. These commands show the setup behind this site in a way you can try yourself; they are a guide, not a transcript of every command I typed during the rebuild.

Step 0: Preparation

You need Node.js, npm, Git and an editor. I use Visual Studio Code. Astro currently requires Node.js 22.12.0 or newer, so check what you have first:

node --version
npm --version
git --version

Once the project is set up, code . opens it in Visual Studio Code, just as it did in my Hugo walkthrough.

Step 1: Create an Astro project

The Astro installer walks you through naming the project and choosing a starter. For a site like mine, I would start with a minimal project rather than a ready-made blog theme. I have enough opinions about how my site should look without spending another weekend undoing somebody else’s theme.

npm create astro@latest
cd your-project-name
npm install

If the installer already installed the dependencies, the last command will simply make sure everything is there. The project will have an astro.config.mjs, a src/ directory for the site and a public/ directory for files served as-is.

Step 2: Run it locally

npm run dev

Open http://localhost:4321. Changes show up as you edit, which is good because I still spend an unreasonable amount of time adjusting CSS and then wondering whether the previous version looked better.

Step 3: Add the parts this site actually uses

Astro can serve plain pages without any of these packages. This particular site uses Tailwind for styling, Three.js for the cube and Motion for some animation.

npm install tailwindcss @tailwindcss/vite three motion
npm install -D typescript @astrojs/check @types/three

I registered the Tailwind Vite plugin in astro.config.mjs and imported Tailwind in the global stylesheet. There is no separate React application sitting beside the blog now. Astro components make up the pages, and the browser only gets JavaScript for features that actually need it.

Step 4: Bring the writing across

This was the part I cared about most. I copied the old Markdown posts into src/content/blog/, kept their original publication dates and set up a schema in src/content.config.ts for the title, description, dates, tags and featured image. The route at src/pages/blog/[...slug].astro turns each file into its own post page. Hugo’s front matter was close enough to be familiar, although some fields needed renaming or tidying up.

Here is the shape of a post on this site:

---
title: "My next post"
description: "A short description for the blog page."
pubDate: 2026-10-24
categories: ["Blog"]
tags: ["Astro"]
---

Save that as src/content/blog/my-next-post.md and it becomes /blog/my-next-post. No hugo new content command this time. I also moved images into public/blog/ and checked the links in the older posts. Moving a site is easy until you realise how many URLs you have been using for years.

The projects have their own collection under src/content/projects/. This means I can add a project in much the same way as I add a post, which was the whole point of bringing the two sites together.

Step 5: Build and publish

npm run astro check
npm run build
npm run preview

The build goes into dist/. Like the old Hugo public/ folder, it is the finished static site that a hosting provider can serve. If you connect the repository to a static host, the build command is npm run build and the publish directory is dist. Then push your changes to Git:

git add .
git commit -m "Rebuild website with Astro"
git push

I would check the old post URLs before switching the domain. Anyone following a link to an old article should reach the article, not a lovely new 404 page.

Was it worth the rabbit hole?

For me, yes. The site now feels like one place rather than a blog and a portfolio politely ignoring each other. I can write about Home Assistant, the NAS, family life or whatever I have been tinkering with, and the projects sit alongside those stories. The cube can be a cube, the blog can stay mostly text and I only have one site to look after.

If you came here for the command-line glamour, I hope I have done my 2023 self proud. If you came here because you are considering a Hugo-to-Astro move, Astro’s migration guide is useful when you get to the content and routing details. My biggest advice is to keep the old URLs in view while you rebuild. The design can always change again. The links people have already saved are harder to get back.

Cheers.