There are several data fetching patterns that can cause Next.js to treat a route as dynamic, even if you’re not explicitly using dynamic segments, headers, or force-dynamic. Here are the main scenarios:
- Using
searchParams
prop in a page component, which makes the route dynamic by default - Using
cookies()
function anywhere in the route, which also triggers dynamic rendering - Using
fetch()
withcache: 'no-store'
option, which opts out of caching - Using third-party libraries or ORMs that don’t use the fetch API under the hood (without proper caching configuration)
- Using
useSearchParams()
hook in a Client Component that’s imported in the route - Using
next/headers
in any component within the route
If you want to ensure a route is statically rendered, you can explicitly set:
export const dynamic = 'force-static'
This will force static rendering and cache the data, even overriding any dynamic APIs by making them return empty values .
Alternatively, if you’re using a database or ORM, you can use the unstable_cache
API to cache database queries:
import { unstable_cache } from 'next/cache'
import { db } from '@/lib/db'
const getData = unstable_cache(
async () => {
return await db.query()
},
['cache-key'],
{ revalidate: 3600 }
)
This allows you to cache database queries that would otherwise make the route dynamic .