# Next.js — Best Practices > Extraído de skills: `next-best-practices` v0.1.0 + `nextjs-patterns` v1.0.0 ## 🏗️ Estrutura de Projeto (App Router) ``` app/ ├── (marketing)/ # Route group — não aparece na URL │ └── page.tsx ├── (dashboard)/ │ ├── layout.tsx # Layout compartilhado do grupo │ ├── [id]/ │ │ └── page.tsx # Página dinâmica │ └── loading.tsx # Suspense boundary automático ├── api/ │ └── route.ts # Route Handler (REST/GraphQL) ├── error.tsx # Error boundary por rota ├── not-found.tsx # Página 404 └── layout.tsx # Root layout (obrigatório) ``` ## 🖥️ Server vs Client Components ```tsx // ✅ Server Component (padrão) — roda no servidor, nenhum JS no cliente async function ProductList() { // DB query acontece no servidor! const products = await db.product.findMany(); return ; } // ✅ Client Component — só quando precisar de interatividade "use client"; import { useState } from "react"; export function Counter() { const [count, setCount] = useState(0); return ; } // ✅ Server Actions — mutations sem criar API routes async function createProduct(formData: FormData) { "use server"; await db.product.create({ data: { ... } }); } ``` ## 📊 Padrões de Data Fetching | Padrão | Quando usar | Exemplo | |--------|-------------|---------| | **Server Component `await`** | Read, página ou componente | `const posts = await db.post.findMany()` | | **Server Actions** | Write/mutations, formulários | `"use server"` + `revalidatePath` | | **Route Handlers** | REST/GraphQL API, webhooks, integrações | `app/api/users/route.ts` | | **`use()` hook** | Ler promise em Client Components | `const data = use(fetchData())` | ### Evitando Data Waterfalls ```tsx // ❌ Ruim — sequencial, cada await aguarda o anterior async function Page() { const user = await getUser(); // 200ms const posts = await getPosts(); // 300ms (só começa após user) return ; } // ✅ Bom — paralelo async function Page() { const [user, posts] = await Promise.all([ getUser(), // começa imediatamente getPosts(), // começa imediatamente ]); return ; } ``` ## 🗄️ Database Client Singleton ```ts // lib/db.ts — criar uma vez por request (Server Component boundary) import { PrismaClient } from '@prisma/client'; const globalForDb = globalThis as unknown as { prisma: PrismaClient }; export const db = globalForDb.prisma ?? new PrismaClient(); if (process.env.NODE_ENV !== 'production') globalForDb.prisma = db; ``` ## 🔄 Caching — 4 Camadas Next.js | Camada | O que cacheia | Controlado por | |--------|---------------|----------------| | **Request Memoization** | `fetch`, `React.cache()` | automático por request | | **Data Cache** | `fetch` responses | `next: { revalidate: 60 }` | | **Full Route Cache** | Render completo | `export const revalidate` | | **Router Cache** | Estado do cliente após navegação | `next/router` | ```ts // Revalidar após 60s fetch(url, { next: { revalidate: 60 } }); // Não cachear (sempre fresh) fetch(url, { next: { revalidate: 0 } }); ``` ## ⚠️ Regra Fundamental > **`"use client"` é uma barreira de escape.** Tudo dentro de um arquivo com essa diretiva > roda no navegador. Tudo SEM ela roda no servidor. Quando possível, fique no servidor.