The detector reads your code
Next.js decides per route whether to render at build time (static) or per request (dynamic). It doesn't ask you — it watches which APIs you call:
| API | Effect |
|---|---|
cookies() | Forces dynamic |
headers() | Forces dynamic |
searchParams | Forces dynamic |
connection() | Explicit opt-in to dynamic |
fetch() without cache | Treated as dynamic data point |
Override when you must
Sometimes the detector picks the wrong default for what you actually want. export const dynamic = 'force-static' errors if the route uses a dynamic API; 'force-dynamic' guarantees per-request rendering even when nothing dynamic is in the code.
Why this matters for cost
A route that's static can be served from CDN with no compute cost per request. A dynamic route runs your code every time. Pick on purpose.