storieasy-logo

Next.js Page Router vs App Router: Modern API Structures Explained (2025)

dhruvesh borad

Info

8 Jun 2025

|

12 min to read

App Router vs Page Router in Next.Js

NextJS

App-v/s-Page

API Router

Nested Routes

Dynamic Routing

Route Groups

Fallback Routing

Next.js has revolutionized web development with its hybrid static & server-rendered architecture. Traditionally, it followed a simple file-based routing mechanism known as the Page Router (/pages). However, with the introduction of App Router in Next.js 13+, a more powerful and flexible approach to routing and APIs was introduced.

πŸ”Ή Section 1: What is Routing in Next.js?

Routing in Next.js controls how users navigate between different pages and how the application handles requests.

βœ… What is Page Router?

The Page Router has existed since the beginning of Next.js. It uses a file-based system inside the /pages directory. Every .js, .ts, or .tsx The file inside this folder automatically becomes a route.

Example:

1/pages/index.tsx  β†’  '/'
2/pages/about.tsx  β†’  '/about'

This also includes API routes:

1/pages/api/user.ts β†’ '/api/user'

βœ… How Page Router Handles API Requests:

In the /pages/api folder, each file becomes a route, and the default export is a handler function.

Example:

1// pages/api/hello.ts
2export default function handler(req, res) {
3  if (req.method === 'GET') {
4    res.status(200).json({ message: "Hello from Page Router API" });
5  }
6}

πŸ”Ή Section 2: Introduction to App Router

In Next.js 13+, Vercel introduced the App Router, a new way to structure applications around React Server Components.

Instead of placing files in /pages App Router uses the /app directory. It allows layouts, server-side streaming, loading/error UI components, and modern API route handling with route.ts.

βœ… Example Folder:

1/app
2  /api
3    /hello
4      route.ts
5  /dashboard
6    /settings
7      page.tsx

βœ… How App Router Handles API:

1// app/api/hello/route.ts
2export async function GET() {
3  return new Response(JSON.stringify({ message: "Hello from App Router" }), {
4    status: 200,
5  });
6}

βœ… Benefits of App Router:

  • Granular control with layouts.
  • React Server Components.
  • Better streaming and performance.
  • Built-in support for loading and error UI.

πŸ”Ή Section 3: Key Differences Between Page Router and App Router

FeaturePage RouterApp Router
Routing Directory/pages/app
Routing SystemFile-basedComponent + file-based
API Routes/pages/api/*.ts/app/api/*/route.ts
HTTP Method HandlersSingle function handlerIndividual functions per HTTP method
Layout SupportLimitedFull support for nested layouts
React Server ComponentsβŒβœ…
Streaming SupportβŒβœ… (Suspense, streaming)
Loading UICustom or manualBuilt-in via loading.tsx
Error Handling_error.tsxerror.tsx per segment
Middleware Supportβœ…βœ…
SEO Meta ManagementManual Built-in with layouts and <Head>

πŸ”Ή Section 4: Real-World API Route Comparison

βœ… Page Router Example: GET blog posts

1// pages/api/blogs.ts
2export default function handler(req, res) {
3  if (req.method === "GET") {
4    res.status(200).json({ posts: ["Post1", "Post2"] });
5  } else {
6    res.status(405).end(); // Method Not Allowed
7  }
8}

βœ… App Router Version:

1// app/api/blogs/route.ts
2export async function GET() {
3  return Response.json({ posts: ["Post1", "Post2"] });
4}

βœ… App Router: Full CRUD

1export async function POST(req: Request) {
2  const body = await req.json();
3  return new Response(JSON.stringify({ created: body }), { status: 201 });
4}
5
6export async function PUT(req: Request) {
7  const body = await req.json();
8  return new Response(JSON.stringify({ updated: body }));
9}
10
11export async function DELETE(req: Request) {
12  return new Response("Deleted successfully", { status: 204 });
13}

πŸ”Ή Section 5: When Should You Use Each Router?

βœ… Page Router:

  • Simpler apps or websites.
  • When backward compatibility matters.
  • Learning or prototyping.

βœ… App Router:

  • Enterprise-level applications.
  • Need for layouts, streaming, and server rendering.
  • Want modular, scalable APIs.

πŸ”Ή Section 6: Migrating from Page Router to App Router

βœ… Step-by-Step Plan:

  1. Create a new /app directory.
  2. Slowly port your pages from /pages to /app.
  3. Replace /pages/api routes with /app/api/.../route.ts.
  4. Use layout.tsx, loading.tsx, error.tsx Where necessary.
  5. Test and clean up /pages.

βœ… Common Pitfalls:

  • Don’t forget to update the dynamic route syntax (e.g., [id].tsx β†’ [id]/page.tsx).
  • Handle React Server Component restrictions (can’t use useState, etc.).

πŸ”Ή Section 7: Best Practices for API Route Management

βœ… Folder Naming:

Use RESTful naming conventions.

1/app/api/posts/route.ts
2/app/api/users/[id]/route.ts

βœ… HTTP Method Isolation:

Separate logic by method.

1export async function GET(req: Request) { /* Read */ }
2export async function POST(req: Request) { /* Create */ }

βœ… Use Utility Functions:

Organize logic into shared files:

1// lib/db.ts
2export const getDB = async () => { ... };
3
4// app/api/user/route.ts
5import { getDB } from "@/lib/db";

πŸ”Ή Section 8: Performance Considerations

  • App Router uses server rendering by default = reduced bundle size.
  • Uses React streaming + Suspense.
  • Optimized for performance-first architecture.

βœ… Tips:

  • Use cache and revalidate options in fetch.
  • Optimize layouts to minimize re-renders.
  • Use loading.tsx to reduce LCP (Largest Contentful Paint).

πŸ”Ή Section 9: SEO Handling in App vs Page Router

βœ… Page Router SEO:

1import Head from 'next/head';
2
3<Head>
4  <title>Home | My Site</title>
5  <meta name="description" content="..." />
6</Head>

βœ… App Router SEO:

1// app/page.tsx
2import { Metadata } from 'next';
3
4export const metadata: Metadata = {
5  title: 'Home | My Site',
6  description: 'This is the homepage',
7};

This supports:

  • Dynamic OG tags
  • Open Graph images
  • SEO at the layout or page level

πŸ”Ή Section 10: The Future of Routing in Next.js

  • Page Router is still supported, but App Router is the recommended standard going forward.
  • New features include App Router.
  • If starting a new project, use App Router.

πŸ”Ή Section 11: Dynamic API Routes in Page Router vs App Router

Dynamic API routes allow you to capture parameters from the URL and handle requests accordingly. This is useful for CRUD operations, user profiles, blog post details, etc.

βœ… Page Router: Dynamic API Routes

In the Page Router (/pages/api), dynamic routes are created by wrapping the filename in square brackets ([]).

πŸ“ File Structure:

1/pages/api/user/[id].ts

πŸ“¦ Example Code:

1  // pages/api/user/[id].ts
2export default function handler(req, res) {
3  const { id } = req.query;
4
5  if (req.method === 'GET') {
6    res.status(200).json({ userId: id });
7  } else {
8    res.status(405).end(); // Method Not Allowed
9  }
10}

βœ… Key Points:

  • req.query It is used to get dynamic values like id.
  • You need to handle HTTP methods manually (GET, PUT, etc.).
  • Route: /api/user/123 will return { userId: "123" }.

βœ… App Router: Dynamic API Routes

In the App Router, dynamic routes are created using folder names wrapped in square brackets.

πŸ“ File Structure:

bashCopyEdit

1/app/api/user/[id]/route.ts

πŸ“¦ Example Code:

1// app/api/user/[id]/route.ts
2export async function GET(request: Request, context: { params: { id: string } }) {
3  const { id } = context.params;
4
5  return Response.json({ userId: id });
6}

βœ… Key Points:

  • context.params Provides access to the dynamic segment.
  • Each method (GET, POST, etc.) is handled as a separate exported function.
  • Route: /api/user/123 will return { userId: "123" }.

🧠 Comparison Table:

FeaturePage RouterApp Router
Folder/File/pages/api/user/[id].ts/app/api/user/[id]/route.ts
Access Paramreq.query.idcontext.params.id
HTTP Method SeparationSingle handler with if blocksExported per-method functions (GET, POST)
Code ReusabilityNeeds custom helpersCleaner structure using isolated functions

πŸ” Bonus: Handling POST with Dynamic ID (App Router)

1// app/api/user/[id]/route.ts
2export async function POST(request: Request, context: { params: { id: string } }) {
3  const { id } = context.params;
4  const body = await request.json();
5
6  return Response.json({
7    message: `Data updated for user ${id}`,
8    newData: body,
9  });
10}

βœ… Best Practices

  • πŸ—‚ Folder Clarity: Always keep dynamic API routes in clearly named folders ([id], [slug]).
  • 🧼 Validate Input: Use zod or custom logic to validate dynamic route params.
  • πŸ” Secure: Protect against invalid or unauthorized access using middleware or logic checks.
  • πŸš€ Cache control: Use headers like Cache-Control or Next.js revalidate where needed.

🎯 Conclusion

Both routing systems serve their purpose. However, as we move deeper into 2025, the App Router is the future of Next.js development, offering unmatched flexibility, speed, and developer experience.

Understanding their API route structures, limitations, and best practices gives developers the confidence to build high-performance web applications.

Newsletter

Subscribe to our newsletter and get our latest updates.

Share with your friends: