Next.js App Router
Applies to Next.js 14+ with app/ directory and TypeScript.
File conventions
app/layout.tsx— required root layout. Must include<html>and<body>.app/page.tsx— route entry. Default is a React Server Component (RSC).app/loading.tsx— streaming fallback for the segment.app/error.tsx— must be a Client Component ('use client'), receives{ error, reset }.app/not-found.tsx— 404 UI.app/route.ts— Route Handler (API). ExportGET,POST, etc.- Dynamic:
app/blog/[slug]/page.tsxgets{ params: { slug: string } }. - Groups:
app/(marketing)/about/page.tsx— URL unaffected. - Parallel:
app/@modal/page.tsx+layout({ modal }). Intercepting:app/(.)photo/[id]/page.tsx.
Rules
- Server Components by default. Add
'use client'only when you need hooks, events, or browser APIs. Keep client boundaries small — push them to leaves. paramsandsearchParamsare async in Next 15:await params.- Never import a Server Component into a Client Component directly if it uses server-only features — pass it as
children/propsinstead. - Use
next/linkfor navigation,next/navigation(useRouter,usePathname) only in Client Components. Useredirect()/notFound()fromnext/navigationin Server Components. - Colocate:
page.tsx,loading.tsx,error.tsxper segment. Shared UI goes incomponents/, not inapp/unless routed.
Patterns
// app/blog/[slug]/page.tsx — Next 15 async params
type Props = { params: Promise<{ slug: string }> };
export default async function BlogPost({ params }: Props) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) notFound();
return <article>{post.title}</article>;
}
export async function generateStaticParams() {
const slugs = await getAllSlugs();
return slugs.map((slug) => ({ slug }));
}
// app/error.tsx — must be a Client Component
'use client';
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<h2>Something went wrong</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
}
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Checklist
- Correct file name and segment placement?
- Client directive only where needed?
-
loading.tsx/error.tsxfor async segments? -
generateStaticParams+generateMetadatawhere SEO matters? - No
useRouterfromnext/router(pages-router import)?