Introduction
For years, hand-coding a website was the gold standard for developers who wanted full control over every line of HTML, CSS, and JavaScript. It offered unmatched flexibility and a deep understanding of the codebase. But as websites grow, more pages, more content, more complexity, that hand-coded approach can become a maintenance nightmare. You find yourself copying and pasting navigation bars, updating footers across dozens of files, and manually optimizing assets for performance.
That's exactly the situation the author of the How-To Geek article found themselves in. Their website, last redesigned around 2018, had grown from supporting six or seven books to many more. The manual patching and adding had become unsustainable. The solution? Rebuilding the entire site with Astro, a modern static site generator that promises speed, simplicity, and a better developer experience.
In this post, we'll dissect that migration journey, explore the technical decisions behind it, and show you how you can apply the same principles to your own projects. Whether you're maintaining a personal blog, a portfolio, or a documentation site, the lessons here are directly applicable.
Enter Astro: The Static Site Generator That Respects Your Code
Astro is a relatively new static site generator that has quickly gained popularity among frontend developers. Its core philosophy is simple: ship zero JavaScript by default, and only load client-side scripts when absolutely necessary. This approach leads to incredibly fast page loads and a smaller carbon footprint.
But what makes Astro particularly appealing for rebuilding a hand-coded website is its component-based architecture. You can create reusable components for headers, footers, cards, and layouts, then compose them into pages. This eliminates the repetitive boilerplate that plagues hand-coded sites.
The Migration Process: Step by Step
Let's walk through the actual steps the author took to rebuild their site with Astro. We'll focus on the technical decisions and code examples that made the transition successful.
Step 1: Setting Up the Astro Project
First, you need to initialize a new Astro project. The official CLI makes this straightforward:
npm create astro@latest my-new-site
During setup, you'll be prompted to choose a template. For a content-heavy site, the "Blog" template is a great starting point. It includes Markdown support, RSS feed generation, and a basic layout.
Once the project is created, you can start customizing the structure. The key folders are:
src/pages/, Each file here becomes a route.src/layouts/, Reusable layout components.src/components/, Smaller UI components.public/, Static assets like images and fonts.
Step 2: Extracting the Layout
In a hand-coded site, every page likely contains the same <header>, <nav>, and <footer> markup. With Astro, you create a single layout component that wraps your page content.
---
// src/layouts/BaseLayout.astro
export interface Props {
title: string;
description?: string;
}
const { title, description } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
{description && <meta name="description" content={description} />}
<link rel="stylesheet" href="/styles/global.css" />
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/blog">Blog</a>
<a href="/about">About</a>
</nav>
</header>
<main>
<slot /> <!-- Page content goes here -->
</main>
<footer>
<p>© 2025 My Site</p>
</footer>
</body>
</html>
Now every page can use this layout with just a few lines:
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="About Me" description="Learn more about the author.">
<h1>About Me</h1>
<p>I'm a frontend developer who loves Astro.</p>
</BaseLayout>
This single change eliminates hundreds of lines of duplicated HTML across the site.
Step 4: Reusable Components for UI Elements
Beyond layouts, Astro components let you encapsulate any UI pattern. For example, a book card component that displays a cover image, title, and description can be reused across multiple pages.
---
// src/components/BookCard.astro
export interface Props {
title: string;
cover: string;
description: string;
url: string;
}
const { title, cover, description, url } = Astro.props;
---
<article class="book-card">
<img src={cover} alt={title} loading="lazy" />
<h3>{title}</h3>
<p>{description}</p>
<a href={url}>Learn More</a>
</article>
<style>
.book-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 1rem;
max-width: 300px;
}
.book-card img {
width: 100%;
height: auto;
border-radius: 4px;
}
</style>
Now you can use this component anywhere:
<BookCard
title="Astro for Beginners"
cover="/images/astro-book.jpg"
description="A comprehensive guide to building fast websites with Astro."
url="/books/astro-for-beginners"
/>
This component-based approach not only saves time but also ensures visual consistency across the site.
Performance Gains: What the Numbers Say
One of the most compelling reasons to migrate to Astro is performance. By shipping zero JavaScript by default, Astro pages load incredibly fast. Let's look at some typical improvements.

SEO and Accessibility Improvements
Rebuilding with Astro also opens the door to better SEO and accessibility practices. Here are some specific improvements you can implement.
Semantic HTML and Structured Data
Astro encourages writing semantic HTML because you're composing components rather than copying and pasting. You can easily add structured data (JSON-LD) to your pages for better search engine understanding.
---
// src/components/SEO.astro
const { title, description, url, image } = Astro.props;
---
"@context": "https://schema.org",
"@type": "WebPage",
"name": title,
"description": description,
"url": url,
"image": image,
})} />
Then include this component in your layout:
<SEO title={title} description={description} url={Astro.url} image="/og-image.jpg" />
Automatic Sitemap Generation
Astro has an official sitemap integration that generates a sitemap.xml file at build time. This is crucial for SEO because it helps search engines discover all your pages.
npm install @astrojs/sitemap
Then add it to your astro.config.mjs:
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [sitemap()],
});
That's it. Every page in your src/pages/ directory will be included in the sitemap automatically.
The Developer Experience: Why Astro Wins
Beyond performance, the developer experience of working with Astro is a major reason to migrate. Here are some aspects that the How-To Geek author likely appreciated.
Hot Module Replacement (HMR)
When you're developing locally, Astro's dev server provides instant feedback. Change a component, and the browser updates without a full page reload. This is a huge productivity boost compared to manually refreshing the browser after every edit.
Integration Ecosystem
Astro has a growing ecosystem of integrations for popular tools:
- Tailwind CSS: For utility-first styling.
- React, Vue, Svelte: Use your favorite framework components inside Astro.
- MDX: Embed React components directly in Markdown.
- Image optimization: Automatic resizing and format conversion.
- RSS feed: Generate RSS feeds from your content collections.
This means you're not locked into a single framework. You can use the best tool for each job.
TypeScript Support
Astro has first-class TypeScript support. You can define props interfaces for your components, which catches errors at build time rather than runtime.
---
interface Props {
title: string;
date: Date;
excerpt: string;
tags: string[];
}
const { title, date, excerpt, tags } = Astro.props;
---
<article>
<h2>{title}</h2>
<time datetime={date.toISOString()}>{date.toLocaleDateString()}</time>
<p>{excerpt}</p>
<ul>
{tags.map(tag => <li>{tag}</li>)}
</ul>
</article>
This catches type errors early and makes your code more maintainable.
Common Pitfalls and How to Avoid Them
Migrating from a hand-coded site to Astro is generally smooth, but there are a few common pitfalls to watch out for.
1. Over-Engineering the Component Tree
It's tempting to create a component for everything, even a single paragraph. But that can lead to unnecessary complexity. Start with the most repetitive elements (layout, navigation, cards) and only create components when you see a pattern repeating three or more times.
2. Ignoring the Build Process
Astro generates a static site, but you still need to configure the build process. Make sure your astro.config.mjs includes the correct site URL for the sitemap, and that your image optimization settings match your needs.
3. Not Using Content Collections for Structured Data
If you have a list of items (books, blog posts, portfolio pieces), use Content Collections. They provide type safety, automatic pagination, and easy filtering. Manually listing items in a component is a step backward.
4. Forgetting About 404 Pages
Hand-coded sites often have a custom 404 page. In Astro, you create a 404.astro file in src/pages/. It will be served automatically for any route that doesn't exist.
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="Page Not Found">
<h1>404</h1>
<p>Sorry, the page you're looking for doesn't exist.</p>
<a href="/">Go back home</a>
</BaseLayout>
Real-World Results: What the Author Achieved
The How-To Geek article provides a candid look at the migration process. The author didn't just rebuild the site, they also improved the content structure, added new features, and optimized for performance.
Conclusion: Is Astro Right for Your Hand-Coded Site?
If you're maintaining a hand-coded website that has grown beyond a few pages, migrating to Astro is likely a smart move. The benefits are clear:
- Faster development: Reusable components and Markdown content reduce repetitive work.
- Better performance: Zero JavaScript by default leads to lightning-fast pages.
- Improved SEO: Automatic sitemaps, structured data, and optimized images boost search rankings.
- Easier maintenance: Update a component once, and it changes everywhere.
The migration process itself is straightforward. Start by setting up a new Astro project, extract your layout into a component, then convert your pages to Markdown or Astro files. Use Content Collections for structured data, and take advantage of the integration ecosystem for images, SEO, and more.
Astro isn't just a tool, it's a philosophy. It respects the craftsmanship of hand-coded sites while providing the automation and scalability that modern web development demands. If you're ready to leave the copy-paste cycle behind, give Astro a try.

