Next.js 15 is the biggest update since the App Router. Turbopack is now the default bundler. Partial Prerendering combines static and dynamic content. Server Actions are stable. The framework is faster, simpler, and more production-ready than ever.
What's New in Next.js 15
- Turbopack — default dev server bundler, 10x faster than webpack
- Partial Prerendering (PPR) — static shell + dynamic holes, one request
- Server Actions stable — form mutations without API routes
- Improved caching — fetch requests no longer cached by default
- React 19 — use() hook, async components, improved Suspense
Turbopack — 10x Faster Dev Server
npx create-next-app@latest my-app
cd my-app && npm run dev
# Turbopack is the default — no flag needed
| Metric | Webpack | Turbopack |
|---|---|---|
| Cold start | 4.2s | 0.4s |
| HMR (file change) | 350ms | 35ms |
| Route change | 800ms | 80ms |
Partial Prerendering — Static + Dynamic in One Request
// app/products/page.tsx
import { Suspense } from "react";
// This component is STATIC — prerendered at build time
function ProductHeader() {
return <h1>Our Products</h1>;
}
// This component is DYNAMIC — renders at request time
async function ProductList() {
const products = await db.products.findMany({
where: { inStock: true },
});
return (
<ul>
{products.map(p => <li key={p.id}>{p.name} — ${p.price}</li>)}
</ul>
);
}
export default function ProductsPage() {
return (
<div>
<ProductHeader /> {/* Served instantly from CDN */}
<Suspense fallback={<ProductSkeleton />}>
<ProductList /> {/* Streams in when ready */}
</Suspense>
</div>
);
}
The static shell loads instantly. The dynamic product list streams in. One request, one response, zero layout shift.
Server Actions — Mutations Without API Routes
// app/actions.ts
"use server";
export async function createTodo(formData: FormData) {
const title = formData.get("title") as string;
await db.todos.create({ data: { title, completed: false } });
revalidatePath("/todos");
}
// app/todos/page.tsx
import { createTodo } from "../actions";
export default function TodoPage() {
return (
<form action={createTodo}>
<input name="title" placeholder="New todo" required />
<button type="submit">Add</button>
</form>
);
}
No fetch('/api/todos', { method: 'POST' }). The form calls the server function directly. Works without JavaScript. Progressive enhancement for free.
Server Components (Default)
// This is a SERVER component by default — runs on the server
// No "use client" directive needed
async function Dashboard() {
const metrics = await db.metrics.findMany();
const user = await getCurrentUser();
return (
<div>
<h1>Welcome, {user.name}</h1>
<MetricsGrid data={metrics} />
<ClientChart data={metrics} /> {/* Only this needs "use client" */}
</div>
);
}
When to Choose Next.js 15
Choose Next.js when:
- You need the largest React ecosystem and community
- SEO + performance matter (PPR is best-in-class)
- You want one framework for static, dynamic, and streaming
- Vercel deployment with zero config
Skip Next.js when:
- You don't need SSR (use Vite + React)
- You prefer simpler mental model (Remix, SvelteKit)
- You want smaller bundle (Astro for content sites)
Start here: nextjs.org
Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors
Top comments (0)