Files
pulse-libs/skills/nextjs-patterns/references/routing-patterns.md
T
Pulse ae39e45460 feat: biblioteca inteligente libs/ + 5 novas skills (20 skills total)
NOVAS SKILLS:
- next-best-practices      v0.1.0  (CLEAN) — Next.js App Router, RSC, caching, data
- nextjs-patterns          v1.0.0  (CLEAN) — Next.js 15: Server Actions, route handlers
- vite                     v1.0.0  (CLEAN) — env vars, aliases, proxy, CJS compat
- uncle-bob                v1.0.0  (CLEAN) — Clean Code, SOLID, Clean Architecture
- clean-code-review        v1.0.0  (CLEAN) — naming, guard clauses, anti-patterns, refactoring
- vue                      v1.0.0  (CLEAN) — Vue framework
- vue-composition-api-best-practices v1.0.0 (CLEAN) — composables, Pinia, reactivity

BIBLIOTECA INTELIGENTE libs/ (10 dominios, 11 arquivos):
- typescript/ — TS safe + generics gotchas
- react/ — Next.js App Router + Vite config
- vue/ — Composition API + Pinia
- linux/ — System diagnostic cheatsheet
- database/ — PostgreSQL + MySQL patterns
- browser/ — Chromium CLI + E2E testing
- security/ — SAST audit (OWASP Top 10)
- best-practices/ — Clean Code + SOLID + Clean Architecture
- deploy/ — Docker multi-stack + OpenClaw ops
- + INDEX.md como guia de navegacao

.learnings/ — LRN-20260519-003 criado (biblioteca compartilhada)
2026-05-19 21:03:25 -03:00

3.0 KiB

Next.js 15 Routing Patterns

App Router Fundamentals

File Purpose
page.tsx Unique UI for a route, makes it publicly accessible
layout.tsx Shared UI; does NOT re-render on navigation
template.tsx Like layout but re-renders on navigation
loading.tsx Instant loading state (React Suspense)
error.tsx Error UI boundary (must be Client Component)
not-found.tsx 404 UI
route.ts API endpoint (GET, POST, etc.)

Route Groups

app/
  (auth)/
    login/page.tsx    → /login
    register/page.tsx → /register
  (app)/
    layout.tsx        ← shared auth-required layout
    dashboard/page.tsx → /dashboard

Route groups (name) organize routes without affecting the URL.

Dynamic Routes

// app/blog/[slug]/page.tsx
export default function Post({ params }: { params: { slug: string } }) {
  return <h1>{params.slug}</h1>
}

// Generate static routes at build time
export async function generateStaticParams() {
  const posts = await fetchAllPosts()
  return posts.map(p => ({ slug: p.slug }))
}

Catch-All & Optional Catch-All

app/shop/[...categories]/page.tsx   → /shop/a/b/c
app/shop/[[...categories]]/page.tsx → /shop AND /shop/a/b/c

Parallel Routes (Advanced)

app/
  @team/page.tsx
  @analytics/page.tsx
  layout.tsx           ← receives { team, analytics } props
// layout.tsx
export default function Layout({ children, team, analytics }) {
  return (
    <div>
      {children}
      <aside>{team}</aside>
      <aside>{analytics}</aside>
    </div>
  )
}

Intercepting Routes

app/
  feed/page.tsx
  (..)photo/[id]/page.tsx  ← intercepts /photo/[id] when navigated from /feed
  photo/[id]/page.tsx      ← full page on direct URL visit

Useful for modals that maintain background context.

Middleware

// middleware.ts (project root)
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export function middleware(request: NextRequest) {
  const token = request.cookies.get("token")
  if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url))
  }
  return NextResponse.next()
}

export const config = {
  matcher: ["/dashboard/:path*", "/api/protected/:path*"],
}

API Routes (Route Handlers)

// app/api/posts/route.ts
import { NextRequest, NextResponse } from "next/server"

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url)
  const page = searchParams.get("page") ?? "1"
  const posts = await fetchPosts(parseInt(page))
  return NextResponse.json({ posts })
}

export async function POST(request: NextRequest) {
  const body = await request.json()
  const post = await createPost(body)
  return NextResponse.json(post, { status: 201 })
}