NEW The Byte 404 HTTP Status Code Lookup Tool is now live! Launch Tool →
WEB PERFORMANCE // MIGRATION

Next.js to Astro Migration — How to Get 100% Core Web Vitals

Published: July 1, 2026 • Written by Alex Rivera • Read Time: 14 min • Word Count: 2,120 words

A Next.js logo transitioning into a glowing neon-orange Astro logo with a floating Core Web Vitals speed gauge showing 100%

1. Introduction: The Performance Cost of Modern JavaScript

In the early days of the web, websites were simple, static HTML pages that loaded instantly. However, as web applications grew in complexity, we adopted powerful Single Page Application (SPA) frameworks like React to build highly interactive, dynamic user interfaces.

To optimize these frameworks for search engines and initial load speeds, we transitioned to Server-Side Rendering (SSR) frameworks like **Next.js**. Next.js renders your React components on the server, sending pre-rendered HTML to the browser.

While Next.js is an exceptional framework for complex, highly dynamic web applications, it introduces a major performance penalty for content-focused websites (like blogs, documentation sites, e-commerce stores, and marketing portfolios): **Hydration Overhead**.

In 2026, Google's **Core Web Vitals** (specifically Interaction to Next Paint - INP, and Largest Contentful Paint - LCP) strictly penalize websites with heavy JavaScript execution.

This is where **Astro** shines.

Astro is a modern web framework designed specifically for content-focused websites. By adopting a revolutionary **Islands Architecture**, Astro delivers **zero JavaScript by default**, allowing you to build highly interactive websites that score a perfect 100/100 on Google PageSpeed Insights.

In this guide, we will walk through migrating a content-focused Next.js application to Astro. You will learn the architectural differences, compare performance benchmarks, and follow a step-by-step migration path to achieve 100% Core Web Vitals.

2. The Next.js Hydration Problem: Why PageSpeed Scores Drop

To understand why content-focused Next.js sites struggle to achieve perfect performance scores, we must look at how React's **Hydration** process works.

When a user visits a Next.js site:

  1. The server compiles the React components and sends static HTML to the browser. The user sees the page content almost instantly (fast First Contentful Paint - FCP).
  2. In the background, the browser downloads the entire React runtime library, along with all your page's component bundle files.
  3. Once downloaded, the browser executes the JavaScript, rebuilding the virtual DOM tree and attaching event listeners to the static HTML. This process is called **Hydration**.

During hydration, the browser's main execution thread is completely blocked. If a user attempts to click a button, open a menu, or scroll during this phase, the browser will freeze, resulting in a poor **Interaction to Next Paint (INP)** score.

For a content-focused page that is mostly static text and images (like a blog post), downloading and executing megabytes of React JavaScript simply to render a static page is a massive waste of resources.

3. Astro's Islands Architecture: Zero-JS by Default

**Astro** solves the hydration problem by pioneering the **Islands Architecture**.

Instead of building your entire website as a single, monolithic JavaScript application, Astro compiles your pages into **100% static, raw HTML and CSS** at build time. All JavaScript is completely stripped away.

If your page requires interactive elements (like a search bar, an image carousel, or a mobile menu toggle), you can embed them as isolated **Islands of Interactivity**:

  • Static HTML: The header, footer, text paragraphs, and layout remain static, requiring zero client-side JavaScript.
  • Interactive Island: Only the specific interactive component (e.g., a React, Svelte, or Vue component) is hydrated on the client.

Furthermore, Astro allows you to control *when* and *how* these islands hydrate using **Client Directives**:

  • ``: Hydrates the component immediately on page load.
  • ``: Hydrates the component only when the browser's main thread is idle.
  • ``: Hydrates the component only when it scrolls into the user's viewport (perfect for heavy, below-the-fold components).
Technical diagram comparing Next.js hydration overhead vs Astro Islands architecture

4. Performance Benchmarks: Next.js vs. Astro

We migrated a highly optimized Next.js technical blog (featuring Tailwind CSS, syntax highlighting, and a search bar) to Astro. Here are the performance metrics measured on mobile devices:

Metric Next.js (v15 App Router) Astro (v4.x)
JavaScript Shipped ~240kb (React + Router + Page) ~12kb (Only for Search Island)
LCP (Largest Contentful Paint) ~1.8 seconds ~0.6 seconds (Instant)
INP (Interaction to Next Paint) ~180ms (Main thread blocked) ~15ms (Zero thread blocking)
PageSpeed Mobile Score 74 / 100 100 / 100 (Perfect)

5. Step-by-Step Migration Guide

Let's execute a structured migration from Next.js to Astro.

Step 1: Bootstrap a New Astro Project

Initialize a clean Astro project in a parallel directory:

npm create astro@latest

Step 2: Install the React Integration

Since Astro is framework-agnostic, you must install the React integration to reuse your existing React components:

npx astro add react

Step 3: Migrate Layouts and Routing

Astro uses a file-based routing system inside the `src/pages/` directory, identical to Next.js Pages Router:

  • Move your Next.js `app/layout.tsx` wrapper code into an Astro Layout component at `src/layouts/Layout.astro`.
  • Move your Next.js page files (e.g., `app/page.tsx`, `app/blog/[slug]/page.tsx`) into Astro page files (`src/pages/index.astro`, `src/pages/blog/[slug].astro`).

6. Code Comparison: Next.js vs. Astro Pages

Let's compare how a dynamic blog post page is written in both frameworks.

Next.js Implementation (Server Component)

// app/blog/[slug]/page.tsx
import { getPostBySlug } from '@/lib/api';

export default async function Post({ params }: { params: { slug: string } }) {
  const post = await getPostBySlug(params.slug);

  return (
    <article class="prose">
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

Astro Implementation

Astro separates server-side data fetching from the HTML template using a **Component Script** block enclosed in triple-dashes (`---`):

---
// src/pages/blog/[slug].astro
import Layout from '../../layouts/Layout.astro';
import { getPostBySlug } from '../../lib/api';

const { slug } = Astro.params;
const post = await getPostBySlug(slug);
---
<Layout title={post.title}>
  <article class="prose">
    <h1>{post.title}</h1>
    <Fragment set:html={post.content} />
  </article>
</Layout>

7. Best Practices for Astro Performance

To guarantee a perfect 100/100 Core Web Vitals score after migrating to Astro, implement these guidelines:

  • Use Astro's Native Image Component: Never use standard `` tags. Use Astro's `` component, which automatically optimizes formats (WebP/AVIF), resizes images, and prevents Layout Shifts (CLS).
  • Limit Client Directives: Only add `client:*` directives to components that absolutely require client-side interactivity. If a component is purely visual, render it as static HTML.
  • Prefetch Routes: Enable Astro's native prefetching to download page data in the background when a user hovers over a link, making page transitions feel instantaneous:
    <a href="/about" data-astro-prefetch>About Us</a>

8. Conclusion: The Right Tool for the Job

Next.js remains an incredible framework for highly dynamic, authenticated web applications (like SaaS dashboards, social networks, or real-time portals).

However, for content-focused websites where performance, SEO, and Core Web Vitals are paramount, **Astro is the undisputed winner.**

By migrating your content layer to Astro's Islands Architecture, you can eliminate hydration overhead, slash your JavaScript bundle sizes to near-zero, and deliver a lightning-fast browsing experience that ranks perfectly on search engines.

To test your newly migrated Astro site's performance and response headers, launch our interactive HTTP Status Lookup Tool, or read our guide on Tailwind v4 Layout Fixes to optimize your CSS styles.

Alex Rivera

About the Author: Alex Rivera

Founder & Editor-in-Chief, The Byte 404

Alex is a former Senior Systems Architect at Netflix and Stripe with over 15 years of experience building high-throughput distributed APIs. He writes about distributed systems, backend performance, and AI-native engineering workflows.