Verified migration
Next.js Pages Router → App Router, verified by the real compiler.
Refactyl migrates a Next.js Pages Router project to the App Router, targeting Next 14, the stable production target. pages/ maps to app/ deterministically. _app.tsx and _document.tsx merge into a single root layout. Every converted file passes an App Router lint gate and a real next build before handoff.
No credit card · Docker-sandboxed · Deleted on handoff · How we handle your code →
Why this migration is hard to get right
Data-fetching APIs are replaced, not renamed
getServerSideProps, getStaticProps, and getInitialProps don't exist in the App Router. The equivalent is an async server component that fetches directly. Converting these patterns correctly requires understanding which data is needed per-request vs. statically, and placing 'use client' boundaries correctly so server-only logic never ships to the browser.
_app.tsx and _document.tsx collapse into one layout
Every Pages Router project has a _app and often a _document. The App Router replaces both with a single app/layout.tsx. Merging them (preserving global styles, providers, and <head> setup) requires a coordinated LLM call that reads both files simultaneously. A missing root layout is a build error.
The App Router lint rules are unforgiving
No next/router import in Server Components. No next/head or next/document. Exactly one default export per page or layout. Page default exports may only destructure { params, searchParams }, nothing else. The compiler doesn't always explain these clearly; a build that crashes for the wrong reason stalls a migration for hours.
How Refactyl does it
Path mapping is deterministic: toAppRouterPath converts pages/* to app/* with correct segment brackets (pages/[id].tsx → app/[id]/page.tsx). _app and _document are merged into app/layout.tsx via a single memoized LLM call; a minimal deterministic fallback layout is emitted if generation fails (a missing root layout is a build error). Converted files pass a deterministic App Router lint before acceptance: no pages-era data exports, no next/router|head|document imports, exactly one export default. Unconvertible pages keep their pages/ originals so they remain routable while the rest of the app runs on the App Router.
Compiler: next build · Zero files ship unverified.
// pages/users/[id].tsx
import { GetServerSideProps } from 'next'
interface Props { user: { id: string; name: string } }
export const getServerSideProps: GetServerSideProps = async ({ params }) => {
const user = await fetchUser(params!.id as string)
return { props: { user } }
}
export default function UserPage({ user }: Props) {
return <h1>{user.name}</h1>
}// app/users/[id]/page.tsx
interface Props { params: { id: string } }
export default async function UserPage({ params }: Props) {
const user = await fetchUser(params.id)
return <h1>{user.name}</h1>
}How to verify the quality claim
Benchmark
We haven't published a Next.js Pages Router→App Router benchmark yet. Until we do, you can verify the quality claim in two ways: the JS→TS benchmark shows how the same verify-and-repair pipeline performs against alternatives on real OSS repos. And the migration audit trail on every run shows exactly which files verified, which were repaired, and which were flagged rather than guessed on, so you can judge the output before downloading anything.
Manual / official codemod vs Refactyl
| Concern | Manual / official codemod | Refactyl |
|---|---|---|
| Build gate on handoff | You run next build; errors are your problem | next build passes before you see the diff, or page is flagged |
| _app + _document merge | Manual: read both, write layout.tsx, test providers still work | Memoized LLM merge + deterministic fallback if generation fails |
| App Router lint rules | Discover violations at next build time | Deterministic lint gate catches violations before build |
| 'use client' placement | Easy to misplace: either too broad or missing | Per-file analysis: placed at the lowest correct boundary |
| Unconvertible pages | Silently broken or blocked until manually resolved | pages/ originals preserved; routable alongside app/ pages |
| Target Next version | Codemods target latest, may hit Next 15 async-API surface | Deliberately targets Next 14, the stable synchronous-params target |
FAQ
Next.js Pages Router → App Router migration: common questions
Real questions engineers ask before migrating Next.js Pages Router to App Router, answered honestly.
Ready to migrate?
Run your Next.js Pages Router repo through the real compiler.
One free migration per month, up to 100 files. No credit card. Every file gated by next build, repaired until clean, or clearly flagged with the reason.
No credit card · Docker-sandboxed · Deleted on handoff · Never used for training