Migrating from Next.js Pages Router to App Router is a significant but manageable project. The recommended approach is incremental - both routers can run in parallel in the same Next.js project, so you migrate route by route rather than all at once.
Next.js App Router was introduced in Next.js 13.4 and became stable and recommended in Next.js 14. By 2026, nearly all new Next.js projects use App Router. If you're on Pages Router, here's everything you need to know about migrating.
Key differences
| Concept | Pages Router | App Router |
|---|---|---|
| File convention | pages/index.tsx | app/page.tsx |
| Layout | _app.tsx wraps all pages | layout.tsx per segment |
| Data fetching | getServerSideProps / getStaticProps | async Server Components |
| Client components | All client by default | Server by default, 'use client' to opt in |
| Metadata | next/head in each page | metadata export |
| API routes | pages/api/route.ts | app/api/route/route.ts |
| Loading states | Manual | loading.tsx convention |
| Error boundaries | Manual | error.tsx convention |
| Streaming | Not supported | Built-in with Suspense |
Step 1: Upgrade Next.js
npm install next@latest react@latest react-dom@latest
Step 2: Create the app directory
Both routers coexist. Create an app directory - Next.js serves routes from app when available, falling back to pages for anything not yet migrated.
/app
layout.tsx # Required root layout
page.tsx # Replaces pages/index.tsx when ready
/pages
index.tsx # Still works until removed
about.tsx # Unmigrated pages keep working
api/
auth.ts # API routes in pages/api still work
Step 3: Create the root layout
// app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";
export const metadata: Metadata = {
title: { default: "My App", template: "%s | My App" },
description: "My app description",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<script dangerouslySetInnerHTML={{ __html: `
(function() {
var s = localStorage.getItem('theme');
var sys = matchMedia('(prefers-color-scheme: dark)').matches;
if (s === 'dark' || (!s && sys)) document.documentElement.classList.add('dark');
})();
`}} />
</head>
<body className="bg-background text-foreground">{children}</body>
</html>
);
}
Step 4: Migrate pages one at a time
// Before: pages/about.tsx
export default function AboutPage() {
return <div>About page</div>;
}
// After: app/about/page.tsx
export const metadata = { title: "About" };
export default function AboutPage() {
return <div>About page</div>;
}
Step 5: Migrate data fetching
// Before: Pages Router
export async function getServerSideProps({ params }) {
const post = await fetchPost(params.id);
return { props: { post } };
}
export default function PostPage({ post }) {
return <div>{post.title}</div>;
}
// After: App Router
export default async function PostPage({ params }: { params: { id: string } }) {
const post = await fetchPost(params.id);
return <div>{post.title}</div>;
}
Common migration issues
-
useState/useEffect in Server Components - add
"use client"directive -
next/router vs next/navigation - App Router uses
useRouterfromnext/navigationwith a different API - getStaticPaths → generateStaticParams - function name and return format changed
-
API routes - move from
pages/api/route.tstoapp/api/route/route.tswith named exports (GET,POST) -
next/head → metadata export - export a
metadataobject frompage.tsxinstead
Frequently asked questions
Should I migrate from Pages Router to App Router in 2026?
For active projects, yes. App Router has better performance through React Server Components and simpler data fetching. For stable projects not being actively developed, the migration cost may not be worth the benefit. New projects should always start with App Router.
Can Pages Router and App Router run together?
Yes. This is the recommended migration strategy. Both routers work simultaneously - routes in app/ take precedence over the same routes in pages/. Migrate one route at a time.
Originally published at thekitbase.app
Top comments (0)