Skip to content
Go back

Why I Migrated from Next.js to Astro for My Personal Blog

After running my personal portfolio and blog on Next.js for over two years, I made the decision to migrate to Astro. This wasn’t a decision I took lightly, but after experiencing the benefits firsthand, I can confidently say it was the right choice for my use case. Here’s why I made the switch and what I learned along the way.

Table of contents

Open Table of contents

The Context: What I Had Before

My previous setup was a Next.js application with:

While this setup worked well, I started noticing some pain points as my content grew and my needs evolved.

The Problems with My Next.js Setup

1. Bundle Size and Performance

Despite using SSG, my Next.js site was shipping unnecessary JavaScript to the browser. Even simple blog posts were loading React’s runtime and hydration code, which felt excessive for content that was essentially static.

The lighthouse scores were good, but I knew they could be better without the JavaScript overhead.

2. Complexity for Simple Content

For a blog that was 90% static content, the React component model felt like overkill. I found myself writing components for simple layouts that could have been plain HTML.

Another issue is the underutilization of certain Next.js features like API routes… while they are great for certain applications, such as BFF, for a micro blog they were almost entirely useless.

3. Build Times

As my content library grew, Next.js build times started to increase noticeably. The framework was doing a lot of work that wasn’t necessary for my static content.

4. SEO and Meta Management

While Next.js has good SEO capabilities, managing meta tags and Open Graph images across different post types required more boilerplate than I wanted to maintain.

Why Astro Was the Perfect Fit

1. Zero JavaScript by Default

Astro’s “islands architecture” means that by default, no JavaScript is shipped to the browser unless explicitly needed. For blog posts, this means:

---
// This runs at build time only
const { post } = Astro.props;
---

<article>
  <h1>{post.title}</h1>
  <div set:html={post.content} />
</article>

The result? Significantly smaller bundle sizes and faster page loads.

2. Better Performance Out of the Box

My Lighthouse scores improved across the board:

3. Simplified Content Management

Astro’s content collections made managing blog posts incredibly straightforward:

// content.config.ts
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDatetime: z.date(),
    author: z.string().default('Edgar Montano'),
    tags: z.array(z.string()).default(['others']),
    featured: z.boolean().default(false),
    draft: z.boolean().default(false),
  }),
});

export const collections = { blog };

4. Excellent Developer Experience

5. Built-in Optimizations

Astro includes many optimizations out of the box:

The Migration Process

1. Content Migration

The easiest part was migrating my Markdown content. Astro’s content collections made this straightforward:

# Old structure (Next.js)
/pages/blog/[slug].js
/content/posts/my-post.mdx

# New structure (Astro)
/src/pages/posts/[...slug].astro
/src/data/blog/my-post.md

2. Component Migration

I rewrote my React components as Astro components. Most were simple enough that this was just removing unnecessary state and effects:

<!-- Before (React/Next.js) -->
import { useState } from 'react';

export default function BlogCard({ post }) {
  return (
    <div className="blog-card">
      <h3>{post.title}</h3>
      <p>{post.excerpt}</p>
    </div>
  );
}

<!-- After (Astro) -->
---
const { post } = Astro.props;
---

<div class="blog-card">
  <h3>{post.title}</h3>
  <p>{post.excerpt}</p>
</div>

3. Routing Updates

Astro’s file-based routing was similar to Next.js, so most routes mapped directly. The main difference was using .astro files instead of .js/.tsx.

4. Styling Migration

Since I was already using Tailwind CSS, the styling migration was minimal. Astro has excellent Tailwind support out of the box.

What I Gained

1. Performance

The performance improvements were immediately noticeable:

2. Simplicity

My codebase became significantly simpler:

3. Better SEO

Astro’s built-in SEO features made optimization easier:

4. Faster Development

Conclusion

While Next.js is an excellent framework for dynamic applications, Astro’s focus on static content and performance made it the perfect fit for my use case.

The migration process was smoother than expected, and the performance benefits were immediate and substantial. If you’re running a content-heavy site on Next.js and feeling like you’re over-engineering your solution, consider giving Astro a try.


Share this post on:

Previous Post
Creating an Audio Analyzer with Qdrant Vector Database
Next Post
Creating UDP Client and Server in Go