A Next.js 14 app with a public landing page, a dashboard section with a shared layout, dynamic blog post pages, and working navigation — all using the App Router.
A Next.js 14 app with a public landing page, a dashboard section with a shared layout, dynamic blog post pages, and working navigation — all using the App Router.
Next.js is the leading React framework for production apps. The App Router (introduced in Next.js 13) uses the app/ directory and React Server Components by default. This is the modern way to build Next.js apps.
# Create a new Next.js app npx create-next-app@latest my-app --typescript --tailwind --app --src-dir # Prompts: # Would you like to use ESLint? Yes # Would you like to use import alias? Yes (@/*) cd my-app && npm run dev # Open http://localhost:3000
This is the most important concept in Next.js 14. By default, all components are Server Components — they render on the server and send HTML. Client Components run in the browser and can use hooks and events.
// No 'use client' = Server Component by default // Can: fetch data, access DB directly, use async/await // Cannot: use useState, useEffect, onClick, browser APIs async function getPosts() { const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5') return res.json() } export default async function Home() { const posts = await getPosts() // direct async in server component return ( <main> <h1>Latest Posts</h1> {posts.map((post) => ( <div key={post.id}>{post.title}</div> ))} </main> ) }
'use client' // This makes it a Client Component import { useState } from 'react' export default function Counter() { const [count, setCount] = useState(0) return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button> }
Dynamic routes use brackets: [slug]. Nested layouts let you wrap sections of your app (like a dashboard) in their own persistent UI without affecting other pages.
src/app/ ├── page.tsx → / ├── layout.tsx → root layout (nav + footer) ├── blog/ │ ├── page.tsx → /blog │ └── [slug]/ │ └── page.tsx → /blog/my-post └── dashboard/ ├── layout.tsx → dashboard sidebar layout ├── page.tsx → /dashboard └── settings/ └── page.tsx → /dashboard/settings
interface Props { params: { slug: string } } export default async function BlogPost({ params }: Props) { // params.slug = whatever is in the URL const { slug } = params return ( <article> <h1>Post: {slug}</h1> </article> ) } // Generate static pages at build time export async function generateStaticParams() { return [{ slug: 'hello-world' }, { slug: 'getting-started' }] }
Use Next.js's Link component for client-side navigation. Use the Metadata API for SEO — it statically generates <head> tags without needing a separate library.
import { Metadata } from 'next' import Link from 'next/link' // Dynamic SEO metadata export async function generateMetadata({ params }: Props): Promise<Metadata> { return { title: `${params.slug} | My Blog`, description: `Read about ${params.slug}`, openGraph: { title: params.slug, type: 'article' } } } export default function Nav() { return ( <nav> <Link href="/">Home</Link> <Link href="/blog" prefetch={true}>Blog</Link> <Link href="/dashboard">Dashboard</Link> </nav> ) }
Day 2 is ready when you are.
Want live instruction and hands-on projects? Join the AI bootcamp — 3 days, 5 cities.
The foundations from today carry directly into Day 2. In the next session the focus shifts to Day 2 — building directly on everything covered here.
Before moving on, verify you can answer these without looking:
Live Bootcamp
Learn this in person — 2 days, 5 cities
Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.
Reserve Your Seat →