Migrating from Hugo to Astro
· Astro
Back in 2024, I set up this site with Hugo and was impressed by its speed and simplicity. But as I continued to work with it, I found myself wanting more flexibility—particularly the ability to use interactive components and modern JavaScript tooling. I decided to check out Astro, a framework that promises to deliver fast, content-focused websites with the flexibility to use your favorite UI framework when you need it.
tl;dr: I migrated my Hugo site to Astro 5 using the Vitesse theme and switched from DigitalOcean to Netlify for deployment. The migration was pretty straightforward, and I gained access to Vue components, better TypeScript support, and a more familiar JavaScript ecosystem.
Why migrate?
Hugo is great for what it does. It’s fast, has great templating, and handles Markdown content well. But I’m always curious to explore new tech stacks, and I found myself wanting:
- Modern JavaScript tooling - TypeScript support, npm packages, and familiar build tools.
- Interactive components - The ability to use Vue, React, or Svelte components when needed.
- Flexibility - More control over the build process and easier customization without learning Go templates.
Astro delivers on all of these while maintaining a focus on speed and static site generation.
What is Astro?
Astro is a modern static site generator that ships zero JavaScript by default but allows you to add interactivity only where you need it. It supports multiple UI frameworks (Vue, React, Svelte, etc.) in the same project and uses a component-based architecture that feels familiar if you’ve worked with modern JavaScript frameworks.
Key features that sold me:
- Content Collections - Type-safe content management with Zod schemas. Zod lets you define the shape of your data (like “title must be a string, date must be a date”), and TypeScript enforces it at build time. Now I don’t have to worry about typos in frontmatter breaking my site.
- View Transitions - Smooth page transitions without a full SPA
- MDX support - Markdown with the ability to import and use components.
- Islands Architecture - Only hydrate interactive components on the page. “Hydration” allows us to take static HTML and make it interactive by attaching JavaScript event listeners. Astro only does this where you explicitly ask for it, keeping most of the site fast and static.
The migration process
Step 1: Choose a theme
Rather than starting from scratch, I decided to use the Vitesse theme as a starting point. It’s an opinionated Astro starter that comes with:
- Astro 5 and Vue 3 support
- UnoCSS for styling
- TypeScript in strict mode
- Content Collections pre-configured
- Dark mode built-in
I cloned the theme repository and removed the Git history to start fresh:
git clone https://github.com/kieranwv/astro-theme-vitesse.git my-astro-site
cd my-astro-site
rm -rf .git
git init
npm install
This gave me a solid foundation without having to configure everything from scratch.
Step 2: Update content collections
The Vitesse theme already had Content Collections configured, but I needed to adjust the schema to match my Hugo frontmatter. I updated src/content/config.ts to support my existing post metadata:
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
date: z.date(),
description: z.string().optional(),
draft: z.boolean().default(false),
tag: z.string().optional(),
}),
});
const pages = defineCollection({
schema: z.object({
title: z.string(),
description: z.string().optional(),
}),
});
export const collections = { blog, pages };
This gives me type safety and auto-completion for all my content’s frontmatter.
Step 3: Migrate content
The content migration was pretty straightforward. Hugo and Astro both use Markdown files with frontmatter, so I simply:
- Copied my content from Hugo’s
content/directory to Astro’ssrc/content/blog/directory. - Updated any Hugo-specific shortcodes to MDX components where needed.
- Adjusted frontmatter dates to match Astro’s expected format.
Most posts only required minor changes (adjusting date formats, updating a few Hugo shortcodes to MDX components). The shortcodes actually became cleaner as Astro components.
One nice thing about both Hugo and Astro is that they both support Markdown with YAML/TOML frontmatter, so the content files are largely compatible. The main difference is that Hugo uses Go templating and shortcodes, while Astro uses JSX-like syntax and MDX components when you need dynamic content.
Step 4: Configure deployment
I decided to switch from DigitalOcean to Netlify for hosting. Netlify has great Astro support and a generous free tier for static sites. The setup was simple:
- Pushed my code to GitLab.
- Connected the repository to Netlify.
- Netlify automatically detected the Astro project and configured the build settings.
The Vitesse theme already included the @astrojs/netlify adapter in astro.config.mjs, so no additional configuration was needed. Every push to the main branch now triggers an automatic build and deploy.
Build performance
I was curious how Astro’s build times would compare to Hugo. The results:
- Hugo build time: ~150ms
- Astro build time: ~2.5s
Hugo is definitely faster at building. However, Astro’s build time is still quite reasonable, and the developer experience improvements more than make up for the slightly longer builds. HMR during development is instantaneous, which is what I spend most of my time doing anyway.
What I gained
Better DX
Working in the JavaScript ecosystem feels more familiar to me than working with Go. I get to use npm packages, TypeScript, ESLint, and other more familiar tooling.
Vue components
I can now add interactive components where I need them. For example, I can create a SearchBar.vue component and drop it into any page:
---
import SearchBar from '@/components/SearchBar.vue';
---
<SearchBar client:load />
Type safety
Content Collections give me compile-time checking for frontmatter. If I forget a required field or misspell a property, my editor tells me immediately.
Modern CSS and theming
The Vitesse theme came with UnoCSS pre-configured, giving me the benefits of utility-first CSS with better tree-shaking and customization than Tailwind. Tree-shaking means unused CSS gets removed from the final bundle, keeping file sizes small. Dark mode support is built-in and works beautifully.
Better deployment experience
Netlify’s integration with Astro is smooth. They include build previews for pull requests, automatic deployments, and great developer experience out of the box.
What I gave up
Build speed
Hugo’s Go-powered builds are noticeably faster. For large sites, this could be significant. For my small blog, the difference is negligible.
Maturity
Hugo has been around longer and has a larger ecosystem of themes and plugins. Astro is newer but growing rapidly.
Simplicity
Hugo is simpler in some ways. It’s a single binary with no node_modules. Astro brings the complexity (and power) of the modern JavaScript ecosystem.
Should you migrate?
If you’re comfortable with Hugo and don’t need JavaScript interactivity, stick with Hugo. It’s excellent at what it does.
Consider migrating to Astro if you:
- Want to use modern JavaScript frameworks and tools
- Need interactive components on some pages
- Prefer working in the JavaScript ecosystem
- Want better TypeScript support
- Are building a site that’s more than just a blog
For me, the migration was worth it. Using a well-crafted starter theme like Vitesse meant I could focus on migrating content rather than configuration. I now have a flexible foundation that can grow with my needs while maintaining the fast, content-focused approach I loved about Hugo.