Pages and Routing
Pages are the heart of your website - they're what users actually visit. In this guide, you'll learn how pages work in Next.js and how routing connects URLs to code.
What is a Page?
A page is a React component exported from a page.tsx file that becomes accessible at a specific URL.
Simple formula:
Folder path + page.tsx = URL route
Page Anatomy
Every page file follows this pattern:
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>This is the about page!</p>
</div>
)
}
Key parts:
export default- Must export the component as default- Function name - Can be anything (we use descriptive names like
AboutPage) - Return JSX - What displays on the page
Pages in Our Codebase
Homepage
File: app/page.tsx
URL: /
Layout: LandingLayout
import LandingLayout from '@/components/layout/LandingLayout'
export default function Home() {
return (
<LandingLayout>
{/* Hero section */}
{/* Mission section */}
{/* Call to action */}
</LandingLayout>
)
}
Purpose: First page visitors see, marketing-focused
About Page
File: app/about/page.tsx
URL: /about
Layout: ArticleLayout
Purpose: Information about K12worX mission and approach
Contact Page
File: app/contact/page.tsx
URL: /contact
Layout: DefaultLayout
Purpose: Contact form for reaching out
Routing Patterns
Basic Route
app/
programs/
page.tsx → /programs
One folder, one page.
Nested Route
app/
programs/
page.tsx → /programs
student-leaders/
page.tsx → /programs/student-leaders
Folders nest, URLs nest!
Multiple Routes
app/
page.tsx → /
about/page.tsx → /about
contact/page.tsx → /contact
programs/page.tsx → /programs
Each folder with page.tsx creates a route.
Navigation Between Pages
Using Link Component
import Link from 'next/link'
function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
</nav>
)
}
Why Link over <a>:
- Prefetches pages for faster navigation
- Client-side navigation (no full page reload)
- Maintains scroll position
- Better performance
Programmatic Navigation
'use client'
import { useRouter } from 'next/navigation'
function MyComponent() {
const router = useRouter()
const handleClick = () => {
router.push('/about')
}
return <button onClick={handleClick}>Go to About</button>
}
We rarely use this - Link is usually better!
Page Metadata
Set page title and description:
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'About Us - K12worX',
description: 'Learn about the K12worX Learning Jamboree mission',
}
export default function AboutPage() {
return <div>...</div>
}
This sets the <title> tag and meta description for SEO!
Server vs Client Pages
Server Components (Default)
// app/about/page.tsx
// No "use client" directive
export default function AboutPage() {
// Renders on server (build time for us)
return <div>Static content</div>
}
Benefits:
- Faster initial load
- Better SEO
- No JavaScript needed in browser
Limitations:
- No
useState,useEffect - No event handlers (onClick, etc.)
- No browser APIs
Client Components
'use client' // Add this directive
import { useState } from 'react'
export default function ContactPage() {
const [name, setName] = useState('')
return (
<form>
<input value={name} onChange={(e) => setName(e.target.value)} />
</form>
)
}
When to use:
- Need interactivity (forms, buttons)
- Need hooks (useState, useEffect)
- Need browser APIs
Our approach: Start with server components, add 'use client' only when needed.
Loading States
Show loading UI while page loads:
// app/about/loading.tsx
export default function Loading() {
return <div>Loading about page...</div>
}
We don't use this much (our site is static), but good to know!
Error Handling
Catch errors in a page:
// app/about/error.tsx
'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>
)
}
Automatically catches errors in page.tsx!
Common Page Patterns
Pattern 1: Content Page
import ArticleLayout from '@/components/layout/ArticleLayout'
export default function ContentPage() {
return (
<ArticleLayout title="Page Title" description="Description">
<section>
<h2>Section 1</h2>
<p>Content here...</p>
</section>
<section>
<h2>Section 2</h2>
<p>More content...</p>
</section>
</ArticleLayout>
)
}
Pattern 2: Landing Page
import LandingLayout from '@/components/layout/LandingLayout'
export default function LandingPage() {
return (
<LandingLayout>
<div className="hero">
<h1 className="text-6xl">Big Bold Title</h1>
<p className="text-lg">Subtitle</p>
</div>
{/* More sections */}
</LandingLayout>
)
}
Pattern 3: Form Page
'use client'
import DefaultLayout from '@/components/layout/DefaultLayout'
import ContactForm from '@/components/content/ContactForm'
export default function FormPage() {
return (
<DefaultLayout>
<h1>Get in Touch</h1>
<ContactForm />
</DefaultLayout>
)
}
Quick Reference
Create a page:
# 1. Create folder
mkdir app/newpage
# 2. Create page.tsx
touch app/newpage/page.tsx
# 3. Add component
# export default function NewPage() { return <div>...</div> }
# 4. Visit
# http://localhost:3000/newpage
Navigation:
<Link href="/about">About</Link>
Metadata:
export const metadata = {
title: 'Page Title',
description: 'Page description'
}
Next Up
Now let's learn about components - the reusable building blocks:
Quick Links
- ← App Router Explained (chapter not yet written)
- Components Explained →