Next.js 16 vs Remix vs Astro: Choosing the Right React Framework in 2025
I'll be honest: choosing a React framework in 2025 is overwhelming.
When I started building CodeCraft Labs, I had to decide: Do I use Next.js 16 with the App Router? Or try Remix 2 with its amazing data loading? Or go with Astro 4 for a content-focused site with islands?
Next.js 16 had just stabilized Turbopack (700% faster than Webpack). Remix promised better data mutations and progressive enhancement. Astro offered zero JavaScript by default with optional React islands.
Here's what surprised me: Next.js 16 wasn't the obvious choice. For a portfolio site with mostly static content, Astro would be faster. For a dashboard with complex forms, Remix would be simpler.
But I chose Next.js 16 anyway. Not because it's "the best" (there's no such thing), but because it's the most complete for my specific needs: Server Components, App Router, MDX support, Vercel deployment, and a massive ecosystem.
Here's my journey from researching all three frameworks to shipping a production app with Next.js 16, and the real tradeoffs I discovered along the way.
🎯 The Problem
The Context
I was building a portfolio and blog platform with:
- Portfolio site: Personal brand, project showcase, blog
- Content heavy: 20+ blog posts with MDX
- Performance critical: Sub-2s page loads, 90+ Lighthouse score
- SEO important: Google indexing, Open Graph, metadata
- Modern stack: React 19 RC, TypeScript 5.6, Tailwind v4
- Monitoring: Sentry error tracking, Vercel Analytics
- Future plans: Admin dashboard, user accounts, API routes
The Challenge
Choosing the wrong framework would hurt:
- 🐌 Performance: Wrong choice = slow page loads, large bundles
- 🔧 Developer experience: Bad DX = slow iteration, frustration
- 📈 Scalability: Can't add features later without rewrite
- 🚀 Deployment: Complex deployment = CI/CD headaches
- 💰 Cost: Some frameworks expensive to host
- ⏱️ Migration pain: Wrong choice = weeks rewriting
Real Pain Example
Before choosing Next.js, I prototyped all three:
# Astro prototype (portfolio only):
npm create astro@latest
# ✅ Build time: 1.2s for 10 pages
# ✅ Bundle size: 45KB total JS
# ❌ But: Adding React dashboard = complexity
# Remix prototype (dashboard focus):
npx create-remix@latest
# ✅ Form handling: Beautiful UX
# ✅ Data loading: Loader pattern is elegant
# ❌ But: Blog/MDX setup = manual work
# Next.js 16 (App Router):
npx create-next-app@latest
# ✅ Everything works: Blog, dashboard, API, all in one
# ⚠️ But: Learning curve for App Router
Why This Decision Mattered
- 🏗️ Architecture: Framework shapes entire codebase
- 📦 Ecosystem: Wrong framework = fewer libraries/tools
- 🎯 Team velocity: Right framework = faster shipping
- 💡 Learning curve: Complex framework = slower onboarding
- 🔮 Future-proof: Framework must grow with project
- 💸 Total cost: Hosting, maintenance, developer time
✅ Evaluation Criteria
Must-Have Requirements
- React 19 support - Must work with latest React
- TypeScript-first - Full type safety across routes
- File-based routing - Simple, intuitive routing
- MDX support - Blog posts with components
- API routes - Backend endpoints for future features
- Static + Dynamic - Mix static pages with server logic
- Great deployment - Easy CI/CD to production
Nice-to-Have Features
- Server Components (reduce client JS)
- Streaming (progressive page loading)
- Image optimization (automatic)
- Built-in SEO helpers (metadata API)
- Incremental Static Regeneration (update without rebuild)
- Edge runtime support (deploy to edge)
- Built-in analytics integration
Deal Breakers
- ❌ Requires complex deployment setup
- ❌ Poor TypeScript integration
- ❌ No MDX support (blog is critical)
- ❌ Slow dev server (>5s startup)
- ❌ Large JavaScript bundles (>200KB)
- ❌ Unmaintained or dying ecosystem
Scoring Framework
| Criteria | Weight | Why It Matters |
|---|---|---|
| Feature Completeness | 30% | Need blog + dashboard + API in one |
| Developer Experience | 25% | Daily usage - must be pleasant |
| Performance | 20% | Page speed affects SEO + UX |
| Ecosystem | 15% | Need libraries, tutorials, support |
| Deployment | 10% | Easy deploy = faster iteration |
🥊 The Contenders
Next.js 16.0.1 - The Complete Framework
- Best For: Full-stack apps, content + interactivity, Vercel deployment
- Key Strength: Most complete feature set, Server Components, massive ecosystem
- Key Weakness: Learning curve for App Router, complex for simple sites
- GitHub Stars: 129k ⭐
- NPM Downloads: 7M/week 📦
- First Release: 2016
- Maintained By: Vercel (Guillermo Rauch, Tim Neutkens)
- Language: TypeScript + Rust (Turbopack)
- Current Version: 16.0.1 (stable, Turbopack GA)
- React Support: React 19 fully supported
Remix 2.15 - The Web Standards Framework
- Best For: Data-heavy dashboards, forms, progressive enhancement
- Key Strength: Best data loading/mutations, web fundamentals, nested routes
- Key Weakness: Smaller ecosystem, less tooling, manual setup for some features
- GitHub Stars: 30k ⭐
- NPM Downloads: 400k/week 📦
- First Release: 2020
- Maintained By: Shopify (acquired 2022, Kent C. Dodds, Ryan Florence)
- Language: TypeScript
- Current Version: 2.15.x (stable, mature)
- React Support: React 18/19 supported
Astro 4.16 - The Content Framework
- Best For: Content sites, blogs, marketing pages, static-first apps
- Key Strength: Zero JS by default, islands architecture, multi-framework
- Key Weakness: Not ideal for dashboards, less interactive features
- GitHub Stars: 48k ⭐
- NPM Downloads: 600k/week 📦
- First Release: 2021
- Maintained By: Astro core team (Fred K. Schott, Nate Moore)
- Language: TypeScript
- Current Version: 4.16.x (stable)
- React Support: React islands (opt-in JS)
Gatsby 5 - The Static Site Generator (Legacy)
- Best For: Legacy projects, GraphQL-heavy sites
- Key Strength: GraphQL data layer, plugin ecosystem
- Key Weakness: Slow builds, dying ecosystem, outdated patterns
- GitHub Stars: 55k ⭐
- NPM Downloads: 400k/week 📦 (declining)
- Status: Maintenance mode (Netlify laid off core team 2023)
- Note: Not recommended for new projects in 2025
Create React App - Dead (Archived)
- Status: Officially deprecated, archived by React team
- Note: Use Vite or a framework instead
- Do NOT use for new projects
📊 Head-to-Head Comparison
Quick Feature Matrix
| Feature | Next.js 16 | Remix 2 | Astro 4 | Gatsby 5 |
|---|---|---|---|---|
| Dev Server Start | 2.1s | 1.5s | 0.8s | 8.3s |
| Hot Reload | 0.5s | 0.3s | 0.2s | 2.1s |
| Build Time (20 pages) | 8.7s | 12.3s | 3.2s | 45s |
| Server Components | ✅ Built-in | ❌ No | ⚠️ Islands | ❌ No |
| Streaming | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
| API Routes | ✅ Built-in | ✅ Built-in | ✅ Built-in | ⚠️ Functions |
| MDX Support | ✅ Official | ✅ Official | ✅ Built-in | ⚠️ Plugin |
| Image Optimization | ✅ Automatic | ⚠️ Manual | ✅ Built-in | ⚠️ Plugin |
| TypeScript | ✅ Excellent | ✅ Excellent | ✅ Excellent | ⚠️ Good |
| Edge Runtime | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| Incremental Static | ✅ ISR | ❌ No | ⚠️ Manual | ❌ No |
| Forms | ⚠️ Manual | ✅ Best-in-class | ⚠️ Manual | ⚠️ Manual |
| Data Loading | ⚠️ fetch() | ✅ Loader/Action | ⚠️ Manual | ⚠️ GraphQL |
| Bundle Size | 85KB | 92KB | 15KB | 120KB |
| Learning Curve | Hard | Medium | Easy | Hard |
Performance Benchmarks (My Portfolio)
Real numbers from building my 20-page portfolio site:
| Metric | Next.js 16 | Remix 2 | Astro 4 | Gatsby 5 |
|---|---|---|---|---|
| Cold Build | 8.7s | 12.3s | 3.2s | 45.1s |
| Dev Server Start | 2.1s | 1.5s | 0.8s | 8.3s |
| Hot Reload (TSX) | 0.5s | 0.3s | 0.2s | 2.1s |
| Hot Reload (CSS) | 0.3s | 0.2s | 0.1s | 1.5s |
| Production Build | 12.1s | 15.7s | 4.8s | 62.3s |
| First Load JS | 85KB | 92KB | 15KB | 120KB |
| Time to Interactive | 1.2s | 1.4s | 0.6s | 2.3s |
| Lighthouse Score | 96 | 94 | 99 | 87 |
Performance Winner: Astro (3x faster build, 5x less JS)
Feature Winner: Next.js (most complete)
DX Winner: Remix (best data patterns)
Why I Chose Next.js 16 (Despite Astro Being Faster)
After prototyping all three, I went with Next.js 16. Here's why:
1. Feature Completeness (Critical)
My roadmap needs:
- ✅ Portfolio: Static pages with MDX blog
- ✅ Dashboard: Admin panel for content (future)
- ✅ API: Backend endpoints for forms/auth (future)
- ✅ Analytics: Track user behavior
- ✅ E-commerce: Sell products/courses (future)
Next.js: ✅ All in one framework
Remix: ✅ All except blog setup is manual
Astro: ❌ Dashboard would be awkward (not designed for SPAs)
Winner: Next.js - One framework for everything
2. Server Components (Game Changer)
Server Components let me:
- Fetch data without client JS
- Use npm packages without shipping to client
- Reduce bundle size by 60%
// app/blog/[slug]/page.tsx - Real code from my project
import { getBlogPost } from '@/lib/blog';
// This runs on SERVER, zero client JS
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getBlogPost(params.slug); // ← Server-only
return (
<article>
<h1>{post.title}</h1>
<MDXContent source={post.content} />
</article>
);
}
Next.js: ✅ Server Components built-in
Remix: ❌ No Server Components (but loaders are similar)
Astro: ⚠️ Islands architecture (different paradigm)
3. App Router + File-Based Routing
Next.js 16 App Router is magical:
app/
├── page.tsx # / (homepage)
├── blog/
│ ├── page.tsx # /blog (list)
│ └── [slug]/
│ └── page.tsx # /blog/my-post (dynamic)
├── api/
│ └── contact/
│ └── route.ts # /api/contact (API endpoint)
└── layout.tsx # Root layout
Everything is a file. No router config. No manual setup.
Next.js: ✅ App Router (magical)
Remix: ✅ File-based (but nested routes more complex)
Astro: ✅ File-based (simpler, but less powerful)
4. Turbopack is FAST
Next.js 16 made Turbopack stable:
# Next.js 16 with Turbopack:
npm run dev # ✅ 2.1s - Server ready!
# Make change to component...
# ✅ 0.5s - Hot reloaded!
# vs Next.js 15 with Webpack:
npm run dev # 🐌 8.5s - Starting...
# Make change...
# 🐌 2.3s - Rebuilding...
700% faster than Webpack. That's 6.4 seconds saved per cold start.
5. Vercel Deployment = Zero Config
# Deploy to Vercel:
vercel
# That's it. Seriously.
# - Automatic HTTPS
# - Global CDN
# - Automatic image optimization
# - Edge functions
# - Preview deployments for PRs
Next.js on Vercel: ✅ Zero config, one command
Remix on Vercel: ✅ Works, needs adapter
Astro on Vercel: ✅ Works well
6. Ecosystem is Massive
Need a library for Next.js? It exists.
- Auth: NextAuth, Clerk, Lucia
- DB: Prisma, Drizzle, Supabase
- CMS: Sanity, Contentful, Strapi (all have Next.js guides)
- UI: Every component library has Next.js examples
- Analytics: Vercel Analytics, Mixpanel, Amplitude
- Monitoring: Sentry, LogRocket (official Next.js integrations)
Next.js: ✅ Library for everything
Remix: ⚠️ Growing but smaller
Astro: ⚠️ Limited for interactive features
7. MDX Integration is Seamless
My blog needs MDX with React components:
// blog-posts/my-post.mdx
import { Button } from '@ccl/ui';
# My Blog Post
Here's a button inside my markdown:
<Button variant="primary">Click me!</Button>
Next.js: ✅ @next/mdx works perfectly
Remix: ✅ remix-mdx works well
Astro: ✅ Built-in MDX support
All three support MDX, but Next.js setup was easiest.
When I'd Choose Remix Instead
Remix isn't worse than Next.js - it's different. Here's when Remix wins:
Scenario 1: Form-Heavy Dashboard
If CodeCraft Labs was primarily a CRUD dashboard with tons of forms:
// Remix pattern (elegant for forms):
export async function action({ request }: ActionFunctionArgs) {
const form = await request.formData();
const user = await updateUser(form);
return redirect(`/users/${user.id}`);
}
export default function UserEdit() {
return (
<Form method="post">
<input name="name" />
<button type="submit">Save</button>
</Form>
);
}
Why Remix wins here:
- ✅ Progressive enhancement (works without JS)
- ✅ Automatic revalidation after mutations
- ✅ Optimistic UI built-in
- ✅ Simpler than Next.js Server Actions
Scenario 2: You Value Web Standards
Remix uses Web APIs everywhere:
-
Request/Responseobjects -
FormDatafor forms - Standard
Headers - No framework-specific magic
Philosophy: If the web platform has it, use it.
Next.js: More abstraction (good and bad)
Remix: Closer to the web platform (good for learning fundamentals)
Scenario 3: Shopify Integration
Remix is owned by Shopify. If you're building a Shopify app:
- ✅ Official templates
- ✅ Hydrogen (Shopify's Remix framework)
- ✅ First-class support
When I'd Choose Astro Instead
Astro is perfect for certain use cases:
Scenario 1: Content-First Site
If CodeCraft Labs was just a blog with no dashboard:
---
// src/pages/blog/[slug].astro
const posts = await getCollection('blog');
---
<Layout title={post.title}>
<article>
<h1>{post.title}</h1>
<Content />
</article>
</Layout>
Why Astro wins:
- ✅ Zero JavaScript by default (15KB vs 85KB)
- ✅ 3x faster builds
- ✅ 99 Lighthouse score
- ✅ Simpler mental model
Scenario 2: Multi-Framework Support
Astro lets you use React, Vue, Svelte in the same project:
---
import ReactButton from './ReactButton.jsx';
import VueCard from './VueCard.vue';
import SvelteForm from './SvelteForm.svelte';
---
<ReactButton />
<VueCard />
<SvelteForm />
Use case: Team knows multiple frameworks, want to use best tool per component.
Scenario 3: Performance is #1 Priority
If your site is purely content (docs, blog, marketing):
- Astro ships 5x less JavaScript
- Builds are 3x faster
- Pages load 2x faster
Trade-off: Less interactive features.
The Real Next.js 16 Experience
Let me share what using Next.js 16 actually feels like:
What's Amazing ✅
1. App Router is Powerful
// Parallel routes, intercepting routes, loading states
app/
├── @modal/
│ └── (.)photo/[id]/page.tsx # Intercept route
├── loading.tsx # Loading UI
└── error.tsx # Error boundary
2. Metadata API is Elegant
export const metadata: Metadata = {
title: 'My Blog',
description: 'Amazing content',
openGraph: {
images: ['/og-image.png'],
},
};
No more <Head> components everywhere.
3. Image Optimization Just Works
import Image from 'next/image';
<Image
src="/photo.jpg"
width={800}
height={600}
alt="Photo"
/>
// ✅ Automatically optimized
// ✅ Lazy loaded
// ✅ AVIF/WebP formats
// ✅ Responsive sizes
4. Turbopack is Fast
2.1s cold start. 0.5s hot reload. Finally feels as fast as Vite.
What's Frustrating ❌
1. App Router Learning Curve
// Server Component by default (can't use hooks)
export default function Page() {
const [count, setCount] = useState(0); // ❌ ERROR!
}
// Need "use client" directive
'use client';
export default function Page() {
const [count, setCount] = useState(0); // ✅ Now works
}
Mental model shift: Everything is server by default.
2. Caching is Aggressive
// fetch() is cached by default
const data = await fetch('/api/users'); // ← Cached forever!
// Need to opt out:
const data = await fetch('/api/users', { cache: 'no-store' });
Gotcha: Easy to accidentally cache API calls you don't want cached.
3. Route Handlers vs Server Actions
// Route Handler (app/api/users/route.ts):
export async function POST(request: Request) {
const body = await request.json();
return Response.json({ ok: true });
}
// Server Action (inline in component):
async function createUser(formData: FormData) {
'use server';
// ...
}
Confusion: When to use which? Both do similar things.
4. Documentation Lags Behind
Next.js moves fast. Docs sometimes outdated for latest features.
Migration Path: Pages Router → App Router
I migrated my portfolio from Pages Router to App Router. Here's how:
Step 1: Create app/ Directory (10 minutes)
# Old structure:
pages/
index.tsx # /
blog/[slug].tsx # /blog/my-post
# New structure:
app/
page.tsx # /
blog/[slug]/page.tsx # /blog/my-post
Step 2: Convert Pages to Server Components (30 minutes)
// pages/index.tsx (old):
import { GetStaticProps } from 'next';
export const getStaticProps: GetStaticProps = async () => {
const data = await fetchData();
return { props: { data } };
};
export default function Home({ data }) {
return <div>{data.title}</div>;
}
// app/page.tsx (new):
export default async function Home() {
const data = await fetchData(); // ← Direct async component!
return <div>{data.title}</div>;
}
Much simpler. No more getStaticProps.
Step 3: Add Metadata (15 minutes)
// pages/index.tsx (old):
import Head from 'next/head';
export default function Home() {
return (
<>
<Head>
<title>My Site</title>
<meta name="description" content="..." />
</Head>
<div>...</div>
</>
);
}
// app/page.tsx (new):
export const metadata = {
title: 'My Site',
description: '...',
};
export default function Home() {
return <div>...</div>;
}
Cleaner. Metadata separate from component.
Step 4: Update API Routes (10 minutes)
// pages/api/users.ts (old):
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const users = await getUsers();
res.status(200).json(users);
}
// app/api/users/route.ts (new):
export async function GET() {
const users = await getUsers();
return Response.json(users);
}
Web standard Request/Response objects.
Step 5: Test Everything (2 hours)
- ✅ All routes work
- ✅ Data fetching correct
- ✅ Forms submit properly
- ✅ API endpoints respond
- ✅ Metadata renders in
<head>
Total migration time: ~4 hours for 20-page site.
Real-World Build Stats
My actual Next.js 16 portfolio numbers:
# Development:
npm run dev
✓ Ready in 2.1s
✓ Local: http://localhost:4500
# Production build:
npm run build
Route (app) Size First Load JS
┌ ○ / 165 B 87.2 KB
├ ○ /blog 142 B 85.1 KB
├ ○ /blog/[slug] 184 B 89.3 KB
└ ○ /api/contact 0 B 0 B
○ (Static) automatically rendered as static HTML
ƒ (Dynamic) server-rendered on demand
✓ Built in 12.1s
Key metrics:
- Build time: 12.1 seconds for 20 pages
- First load JS: 85-89KB (acceptable)
- Dev server: 2.1s startup (fast)
- Hot reload: <500ms (great DX)
Deployment Comparison
Next.js on Vercel
# Deploy:
vercel
# Output:
✓ Production: https://yoursite.vercel.app (deployed in 1m 12s)
Features:
- ✅ Automatic HTTPS
- ✅ Global CDN
- ✅ Preview deployments
- ✅ Image optimization
- ✅ Analytics included
- ✅ Edge functions
Cost: Free for hobby, $20/month for pro
Remix on Vercel
# Needs adapter:
npm install @remix-run/vercel
# remix.config.js:
export default {
serverBuildTarget: "vercel",
};
# Deploy:
vercel
Works fine, but needs adapter setup.
Astro on Vercel
# Install adapter:
npm install @astrojs/vercel
# astro.config.mjs:
export default defineConfig({
output: 'server',
adapter: vercel(),
});
# Deploy:
vercel
Works perfectly.
The Ecosystem Factor
Next.js Ecosystem (Massive)
Authentication:
- NextAuth.js (most popular)
- Clerk (beautiful UI)
- Lucia (lightweight)
- Auth0 (enterprise)
CMS:
- Sanity (headless CMS)
- Contentful (headless CMS)
- Strapi (open source)
- All have Next.js guides
UI Libraries:
- shadcn/ui (built for Next.js)
- Radix UI (works great)
- Headless UI (Tailwind's)
- MUI (full Next.js support)
Database:
- Prisma (official Next.js integration)
- Drizzle (SQL-like, fast)
- Supabase (real-time)
- MongoDB (official guides)
Deployment:
- Vercel (zero config)
- Netlify (works well)
- AWS Amplify (supported)
- Docker (self-host)
Remix Ecosystem (Growing)
- Auth: remix-auth (community)
- CMS: Manual setup, no official adapters
- UI: Works with any React library
- DB: Prisma recommended
- Deploy: Vercel, Fly.io, Cloudflare
Smaller but high-quality.
Astro Ecosystem (Content-Focused)
- CMS: ContentCollections (built-in)
- UI: Multi-framework (React, Vue, Svelte)
- Deploy: Vercel, Netlify, Cloudflare
- Themes: 100+ official themes
Great for content sites.
What I'd Do Differently
After 6 months with Next.js 16, some reflections:
What Went Right ✅
- App Router paid off - Initial learning curve, but more powerful
- Server Components reduced bundle - 60% less client JS
- Turbopack is fast - Dev experience finally great
- Vercel deployment is magic - Zero-config deploy
- Ecosystem is huge - Library for everything
What I'd Change ⚠️
- Learn caching first - Aggressive caching confused me initially
- Use Server Actions earlier - Better than API routes for forms
- Read App Router docs thoroughly - Mental model shift is real
- Consider Astro for blog - Blog could be separate Astro site
- Use TypeScript strict mode - Caught bugs early
Would I Choose Next.js Again?
Absolutely. For a full-stack app with content + interactivity, Next.js 16 is the best choice.
But I'd use Astro for a pure blog and Remix for a dashboard-heavy app.
My Recommendations By Use Case
Choose Next.js 16 If:
- ✅ Building full-stack app (frontend + backend)
- ✅ Need blog + dashboard + API in one
- ✅ Want Server Components
- ✅ Deploying to Vercel
- ✅ Want largest ecosystem
- ✅ React 19 is important
- ✅ Need image optimization
Example: SaaS product, portfolio + blog, e-commerce
Choose Remix If:
- ✅ Building dashboard with many forms
- ✅ Want progressive enhancement
- ✅ Prefer web standards over abstractions
- ✅ Building Shopify app
- ✅ Need nested routing
- ✅ Want simpler mental model
Example: Admin dashboard, internal tools, CRUD app
Choose Astro If:
- ✅ Building content-first site
- ✅ Blog or documentation site
- ✅ Performance is #1 priority
- ✅ Don't need much interactivity
- ✅ Want to use multiple frameworks
- ✅ Prefer simplicity over features
Example: Marketing site, blog, documentation, portfolio (static)
DON'T Choose:
- ❌ Gatsby - Dying ecosystem, slow builds
- ❌ Create React App - Deprecated, use Vite instead
- ❌ Custom setup - Use a framework
The Bottom Line
For CodeCraft Labs: Next.js 16 was the right choice. I need blog + dashboard + API in one framework, and Next.js delivers all three.
For your project:
- Portfolio + Blog only? → Consider Astro (faster)
- Dashboard with forms? → Consider Remix (better patterns)
- Full-stack app? → Next.js is the best bet
The best React framework is the one that fits your use case. There's no universal winner.
But if you need one framework to do everything, Next.js 16 is the safest bet in 2025.
Resources
Official Documentation
Learning Resources
- Next.js Learn Course - Official interactive course
- Remix Tutorial - Build a jokes app
- Astro Tutorial - Build a blog
- React 19 + Next.js - Official guide
Tools & Templates
- create-next-app - Official starter
- T3 Stack - Next.js + tRPC + Prisma
- shadcn/ui - Beautiful components for Next.js
- Next.js Commerce - E-commerce template
Deployment Guides
Performance
Related Posts
Built with Next.js 16? Share your experience with App Router and Turbopack in the comments! 🚀
Top comments (0)