JSTAcademy
0 XP
Dashboard
Crash Courses
Next.js App Router Fundamentals
10 min
Basic+150 XP
Crash Courses · Basic

Next.js App Router Fundamentals

Understand the App Router file-system routing and React Server Components.
10 min read+150 XP on completionCert: Next.js Crash Course
Tap any word in the text below to start reading from there.

Next.js App Router Fundamentals

Next.js 15 App Router builds on React Server Components. Every component is a server component by default only opt into client when you need browser APIs or interactivity.

File System Routing

app/
  layout.tsx          ← root layout (html, body)
  page.tsx            ← /
  about/
    page.tsx          ← /about
  courses/
    layout.tsx        ← wraps all /courses/* pages
    page.tsx          ← /courses
    [id]/
      page.tsx        ← /courses/abc123
      loading.tsx     ← Suspense fallback
      error.tsx       ← error boundary

Server Component (Default)

// app/courses/page.tsx — server component, no "use client"
import { getCourses } from '@/lib/courses'

export default async function CoursesPage() {
  const courses = await getCourses()  // direct DB call — no API needed

  return (
    <main>
      <h1>Courses</h1>
      <ul>
        {courses.map(c => <li key={c.id}>{c.title}</li>)}
      </ul>
    </main>
  )
}

Client Component

'use client'  // ← required for hooks and event handlers

import { useState } from 'react'

export function SearchBar({ onSearch }: { onSearch: (q: string) => void }) {
  const [query, setQuery] = useState('')

  return (
    <input
      value={query}
      onChange={e => setQuery(e.target.value)}
      onKeyDown={e => e.key === 'Enter' && onSearch(query)}
      placeholder="Search courses..."
    />
  )
}

Layout

// app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import { Sidebar } from '@/components/Sidebar'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'JST Academy',
  description: 'PhD-level crash courses for modern web development',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Sidebar />
        <main>{children}</main>
      </body>
    </html>
  )
}
0%