Next.js 15 App Router page with streaming, caching, and server data
Scaffold a production App Router page: Server Component data fetching, Suspense streaming for instant TTFB, correct cache strategy (fetch cache vs unstable_cache vs revalidatePath), loading/error boundaries, and generateMetadata — with the non-obvious patterns most tutorials skip.
You are a senior Next.js 15 engineer who optimizes for both DX and Core Web Vitals. Create a new route at `app/[ROUTE]/page.tsx` for a TypeScript App Router project.
Requirements:
- The page is a Server Component. Fetch data from [API/DATA SOURCE] directly in the component body — no client-side useEffect. Type the response with an explicit interface (no `any`, no `as` casts).
- Wrap the slow/data-dependent section in `<Suspense fallback={<Loading />}>` so the shell streams instantly (PPR-ready). If the page has independent data needs (e.g., sidebar + main), fetch them in parallel server components inside separate Suspense boundaries — do NOT waterfall.
- Add sibling files: `loading.tsx` (skeleton matching the real layout, not a spinner) and `error.tsx` (with a `reset` button that calls `reset()` from the error boundary props).
- Export `generateMetadata` that derives a real title and description from the fetched data.
Caching — choose the RIGHT layer and explain your choice:
| Strategy | When to use |
|---|---|
| `fetch(..., { next: { revalidate: 60 } })` | External API, time-based freshness is fine |
| `unstable_cache(fn, [keys], { revalidate, tags })` | DB queries or non-fetch data sources that need tag-based invalidation via `revalidateTag()` |
| `revalidatePath('/route')` | On-demand revalidation after a mutation (Server Action) |
| No cache / `{ cache: 'no-store' }` | User-specific data (behind auth) that must never be shared |
Apply the correct strategy for [API/DATA SOURCE] and add a comment explaining why.
- If any part requires interactivity, extract it into its own `'use client'` child component. Keep the client surface minimal.
- If a modal or sidebar makes sense, show how to use a Parallel Route (`@modal/default.tsx`) intercepted via `(.)` so it overlays without a full navigation.
Return the full contents of each file in separate fenced code blocks. After the code, add a 3-line note: (1) the caching strategy you chose and why, (2) what would change if this data were user-specific, (3) one thing to watch for when deploying to Vercel vs self-hosted.- Source
- promptfork seed
- License
- CC-BY-4.0
- Published
- 6/23/2026