---
name: router-core/search-params
description: >-
validateSearch, search param validation with Zod/Valibot/ArkType adapters,
fallback(), search middlewares (retainSearchParams, stripSearchParams),
custom serialization (parseSearch, stringifySearch), search param
inheritance, loaderDeps for cache keys, reading and writing search params.
type: sub-skill
library: tanstack-router
library_version: '1.166.2'
requires:
- router-core
sources:
- TanStack/router:docs/router/guide/search-params.md
- TanStack/router:docs/router/how-to/setup-basic-search-params.md
- TanStack/router:docs/router/how-to/validate-search-params.md
- TanStack/router:docs/router/how-to/navigate-with-search-params.md
- TanStack/router:docs/router/how-to/share-search-params-across-routes.md
- TanStack/router:docs/router/guide/custom-search-param-serialization.md
---
# Search Params
TanStack Router treats search params as JSON-first application state. They are automatically parsed from the URL into structured objects (numbers, booleans, arrays, nested objects) and validated via `validateSearch` on each route.
> **CRITICAL**: When using `zodValidator()` and Zod v3, use `fallback()` from `@tanstack/zod-adapter`, NOT zod's `.catch()`. Using `.catch()` with the zod adapter makes the output type `unknown`, destroying type safety. This does not apply to Valibot or ArkType (which use their own fallback mechanisms). It also does not apply to Zod v4, which should use `.catch()` and not use the `zodValidator()`.
> **CRITICAL**: Types are fully inferred. Never annotate the return of `useSearch()`.
## Setup: Zod Adapter (Recommended)
```bash
npm install zod @tanstack/zod-adapter
```
```tsx
// src/routes/products.tsx
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
const productSearchSchema = z.object({
page: z.number().default(1).catch(1),
filter: z.string().default(''),
sort: z.enum(['newest', 'oldest', 'price']).default('newest').catch('newest'),
})
export const Route = createFileRoute('/products')({
validateSearch: productSearchSchema,
component: ProductsPage,
})
function ProductsPage() {
// page: number, filter: string, sort: 'newest' | 'oldest' | 'price'
// ALL INFERRED — do not annotate
const { page, filter, sort } = Route.useSearch()
return (