Skip to main content

Jul 2026 · Tutorial · ~12 min read

Next.js App Router Complete Beginner Guide 2026

By Safdar Ali — frontend engineer, Bengaluru

The nextjs app router tutorial gap is real: official docs are reference-heavy, and beginners still think in Pages Router (pages/index.tsx). App Router uses folders in app/ where the file name tells Next.js what to do. I migrated client sites in 2024–2025 and teach this sequence on my YouTube channel. Follow these steps in order — layout, page, loading, then server fetch.

Mental model — folders are routes

Every folder under app/ maps to a URL segment. Special files: page.tsx = UI, layout.tsx = shared shell, loading.tsx = skeleton while slow segments load.

app/
  layout.tsx      → wraps ALL routes
  page.tsx        → URL: /
  about/
    page.tsx      → URL: /about
  blog/
    page.tsx      → URL: /blog
    [slug]/
      page.tsx    → URL: /blog/my-post

No React Router install. Rename a folder, you rename a route. That is the core App Router win.

If you are coming from Create React App, delete the mental model of a single App.tsx with a Switch. You will have multiple layout.tsx files at different depths — root for html/body, nested for dashboard sidebars. Each layout wraps only its subtree.

Step 1 — Root layout (HTML shell once)

// app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "My App",
  description: "Beginner App Router site",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className="min-h-screen bg-white text-neutral-900">
        <header className="border-b p-4">My Site</header>
        <main>{children}</main>
      </body>
    </html>
  );
}

Layouts do not remount when navigating between child pages — perfect for nav bars and fonts. Keep providers that must persist here (theme, analytics).

Step 2 — First page

// app/page.tsx — home route
export default function HomePage() {
  return (
    <section className="p-8">
      <h1 className="text-3xl font-bold">Welcome</h1>
      <p>Your first App Router page — no use client needed.</p>
    </section>
  );
}

Default export must be a component. This is a Server Component unless you add "use client" at the top.

Step 3 — loading.tsx for perceived speed

// app/blog/loading.tsx — shows while blog segment loads
export default function BlogLoading() {
  return (
    <div className="animate-pulse space-y-4 p-8">
      <div className="h-8 w-48 rounded bg-neutral-200" />
      <div className="h-4 w-full rounded bg-neutral-200" />
      <div className="h-4 w-3/4 rounded bg-neutral-200" />
    </div>
  );
}

Next.js wraps the segment in Suspense automatically. Users see skeletons instead of frozen UI — critical on Indian mobile networks.

Step 4 — Server Component fetch (no useEffect)

// app/blog/page.tsx
type Post = { slug: string; title: string };

async function getPosts(): Promise<Post[]> {
  const res = await fetch("https://api.example.com/posts", {
    next: { revalidate: 3600 },
  });
  if (!res.ok) throw new Error("Failed to load posts");
  return res.json();
}

export default async function BlogPage() {
  const posts = await getPosts();
  return (
    <ul className="space-y-2 p-8">
      {posts.map((post) => (
        <li key={post.slug}>
          <a href={"/blog/" + post.slug}>{post.title}</a>
        </li>
      ))}
    </ul>
  );
}
// BEFORE — Pages Router habit (client fetch)
"use client";
useEffect(() => fetch("/api/posts").then(/* ... */), []);

// AFTER — async server component
// Data ready before HTML ships — better SEO and LCP

Deeper caching rules: SSR vs SSG vs ISR. Performance tuning: 60% load time case study.

App Router files — quick comparison table

FilePurposeRequired?
layout.tsxShared UI wrapperRoot required
page.tsxRoute UIYes per route
loading.tsxLoading skeletonOptional
error.tsxError boundaryOptional
not-found.tsx404 UIOptional
route.tsAPI endpointOptional

Step 5 — Add client components only as leaves

// components/CounterButton.tsx
"use client";
import { useState } from "react";

export function CounterButton() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>Clicked {n} times</button>;
}

// app/page.tsx — server page imports client leaf
import { CounterButton } from "@/components/CounterButton";

export default function HomePage() {
  return (
    <section>
      <h1>Home</h1>
      <CounterButton />
    </section>
  );
}

Read RSC vs client components before marking whole pages as client — that is the beginner mistake that balloons bundle size.

Step 6 — Dynamic routes and params

// app/blog/[slug]/page.tsx
type Props = { params: Promise<{ slug: string }> };

export default async function PostPage({ params }: Props) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) return <p>Not found</p>;
  return <article><h1>{post.title}</h1></article>;
}

In Next.js 15, params is a Promise — await it. TypeScript strict mode helps catch forgotten awaits — strict mode guide.

Learning path after this guide

Week 1: layouts + pages + loading. Week 2: server fetch + one dynamic route. Week 3: one client form with Server Action. Week 4: deploy to Vercel and run Lighthouse. If you are choosing between stacks first, read Next.js vs React. Organise folders early with project structure guide.

For AI-assisted coding, see Cursor + Claude workflow — but build this hello-world tree by hand once so file conventions stick.

My production setup

In production I scaffold with root layout, route groups for marketing vs app, loading.tsx on slow segments, and async server pages for public content. This portfolio follows the same pattern — thin app/blog/.../page.tsx files, heavy logic elsewhere.

At my day job, beginners who complete these six steps ship their first internal page in a week — faster than learning Pages Router and relearning later.

The single takeaway

App Router = folders + special files. Layout once, page per route, loading for UX, async server fetch for data. Client components are seasoning, not the main dish.

Related: React 19 features. Contact.

If this helped you

I publish free tutorials and write-ups like this in my spare time — no paywall on the guides. If it saved you an afternoon of trial and error, you can support the work:

More guides on safdarali.in — same author, production-focused.

"Talk is cheap. Show me the code."