How to use query params without suspense in Next.js?
Is there any way to use query params without a suspense in Next.js with cache components enabled?
Perfect! I found the exact information. Let me now create a comprehensive answer based on the source code and documentation.
##Answer
No, you cannot use searchParams directly inside a "use cache" scope in Next.js. However, there is a recommended pattern to handle this.
###The Problem
When you try to access searchParams inside a use cache block, Next.js will throw an error:
Route ${route} used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported.
This is by design because:
searchParamsis runtime request data that can vary per requestuse cacheis designed to cache computed results, which requires deterministic inputs- You cannot have dynamic runtime data inside a cached scope (from source:
packages/next/src/server/request/utils.ts)
###The Solution
Read searchParams outside the cached scope and pass the values as arguments to your cached function or component.
Here's the recommended pattern from the Next.js documentation:
import { Suspense } from 'react'
export default function Page() {
// Create dynamic boundary if needed
return (
<Suspense fallback={<div>Loading...</div>}>
<PageContent />
</Suspense>
)
}
// Component (not cached) reads runtime data
async function PageContent({ searchParams }: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {
const resolvedParams = await searchParams
const foo = resolvedParams.foo
// Pass values as arguments to cached component
return <CachedContent foo={foo} />
}
// Cached component receives data as props
async function CachedContent({ foo }: { foo: string | string[] | undefined }) {
'use cache'
// foo becomes part of the cache key
const data = await fetchData(foo)
return <div>{data}</div>
}
###Key Points:
- Await
searchParamsoutside the cache scope - Read and resolve the promise in a non-cached component - Pass specific values as arguments - Only pass the values you need, not the entire
searchParamspromise - Arguments become part of the cache key - Different argument values will have separate cache entries
- Use
Suspenseif needed - Wrap dynamic components in<Suspense>to define fallback UI
This pattern ensures that your cached content can still be deterministic and prerendered, while allowing you to customize behavior based on query parameters by passing them as arguments.
Sources:
test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts- Test suite showing error scenariospackages/next/src/server/request/utils.ts- Error message implementationdocs/01-app/01-getting-started/06-cache-components.mdx- Official documentation with "With runtime data" exampledocs/01-app/03-api-reference/01-directives/use-cache.mdx- Cache directive reference
END OF POST