diff --git a/docs/router/api/router/retainSearchParamsFunction.md b/docs/router/api/router/retainSearchParamsFunction.md
index eeac38bcd78..18600fd346d 100644
--- a/docs/router/api/router/retainSearchParamsFunction.md
+++ b/docs/router/api/router/retainSearchParamsFunction.md
@@ -15,14 +15,14 @@ If `true` is passed in, all search params will be retained.
```tsx
import { z } from 'zod'
import { createRootRoute, retainSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
rootValue: z.string().optional(),
})
export const Route = createRootRoute({
- validateSearch: zodValidator(searchSchema),
+ // Use the schema directly for Zod v4
+ validateSearch: searchSchema,
search: {
middlewares: [retainSearchParams(['rootValue'])],
},
@@ -32,7 +32,6 @@ export const Route = createRootRoute({
```tsx
import { z } from 'zod'
import { createFileRoute, retainSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
one: z.string().optional(),
@@ -40,7 +39,8 @@ const searchSchema = z.object({
})
export const Route = createFileRoute('/')({
- validateSearch: zodValidator(searchSchema),
+ // Use the schema directly for Zod v4
+ validateSearch: searchSchema,
search: {
middlewares: [retainSearchParams(true)],
},
diff --git a/docs/router/api/router/stripSearchParamsFunction.md b/docs/router/api/router/stripSearchParamsFunction.md
index bfbb57a7406..08164c39ba9 100644
--- a/docs/router/api/router/stripSearchParamsFunction.md
+++ b/docs/router/api/router/stripSearchParamsFunction.md
@@ -18,7 +18,6 @@ title: Search middleware to strip search params
```tsx
import { z } from 'zod'
import { createFileRoute, stripSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
const defaultValues = {
one: 'abc',
@@ -31,7 +30,8 @@ const searchSchema = z.object({
})
export const Route = createFileRoute('/')({
- validateSearch: zodValidator(searchSchema),
+ // for Zod v4, use the schema directly
+ validateSearch: searchSchema,
search: {
// strip default values
middlewares: [stripSearchParams(defaultValues)],
@@ -42,7 +42,6 @@ export const Route = createFileRoute('/')({
```tsx
import { z } from 'zod'
import { createRootRoute, stripSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
hello: z.string().default('world'),
@@ -50,7 +49,8 @@ const searchSchema = z.object({
})
export const Route = createRootRoute({
- validateSearch: zodValidator(searchSchema),
+ // for Zod v4, use the schema directly
+ validateSearch: searchSchema,
search: {
// always remove `hello`
middlewares: [stripSearchParams(['hello'])],
@@ -61,7 +61,6 @@ export const Route = createRootRoute({
```tsx
import { z } from 'zod'
import { createFileRoute, stripSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
const searchSchema = z.object({
one: z.string().default('abc'),
@@ -69,7 +68,8 @@ const searchSchema = z.object({
})
export const Route = createFileRoute('/')({
- validateSearch: zodValidator(searchSchema),
+ // for Zod v4, use the schema directly
+ validateSearch: searchSchema,
search: {
// remove all search params
middlewares: [stripSearchParams(true)],
diff --git a/docs/router/guide/search-params.md b/docs/router/guide/search-params.md
index 53e9cd1c8a1..cbc84c55267 100644
--- a/docs/router/guide/search-params.md
+++ b/docs/router/guide/search-params.md
@@ -196,7 +196,9 @@ For validation libraries we recommend using adapters which infer the correct `in
### Zod
-An adapter is provided for [Zod](https://zod.dev/) which will pipe through the correct `input` type and `output` type
+An adapter is provided for [Zod](https://zod.dev/) which will pipe through the correct `input` type and `output` type.
+
+For Zod v3:
```tsx
import { zodValidator } from '@tanstack/zod-adapter'
@@ -213,13 +215,30 @@ export const Route = createFileRoute('/shop/products/')({
})
```
-The important part here is the following use of `Link` no longer requires `search` params
+With Zod v4, you should directly use the schema in `validateSearch`:
+
+```tsx
+import { z } from 'zod'
+
+const productSearchSchema = z.object({
+ page: z.number().default(1),
+ filter: z.string().default(''),
+ sort: z.enum(['newest', 'oldest', 'price']).default('newest'),
+})
+
+export const Route = createFileRoute('/shop/products/')({
+ // With Zod v4, we can use the schema without the adapter
+ validateSearch: productSearchSchema,
+})
+```
+
+The important part here is the following use of `Link` no longer requires `search` params:
```tsx
```
-However the use of `catch` here overrides the types and makes `page`, `filter` and `sort` `unknown` causing type loss. We have handled this case by providing a `fallback` generic function which retains the types but provides a `fallback` value when validation fails
+In Zod v3, the use of `catch` here overrides the types and makes `page`, `filter` and `sort` `unknown` causing type loss. We have handled this case by providing a `fallback` generic function which retains the types but provides a `fallback` value when validation fails:
```tsx
import { fallback, zodValidator } from '@tanstack/zod-adapter'
@@ -240,7 +259,9 @@ export const Route = createFileRoute('/shop/products/')({
Therefore when navigating to this route, `search` is optional and retains the correct types.
-While not recommended, it is also possible to configure `input` and `output` type in case the `output` type is more accurate than the `input` type
+In Zod v4, schemas may use `catch` instead of the fallback and will retain type inference throughout.
+
+While not recommended, it is also possible to configure `input` and `output` type in case the `output` type is more accurate than the `input` type:
```tsx
const productSearchSchema = z.object({
@@ -457,7 +478,7 @@ Now that you've learned how to read your route's search params, you'll be happy
The best way to update search params is to use the `search` prop on the `` component.
-If the search for the current page shall be updated and the `from` prop is specified, the `to` prop can be omitted.
+If the search for the current page shall be updated and the `from` prop is specified, the `to` prop can be omitted.
Here's an example:
```tsx title="src/routes/shop/products.tsx"
@@ -478,7 +499,7 @@ const ProductList = () => {
If you want to update the search params in a generic component that is rendered on multiple routes, specifying `from` can be challenging.
-In this scenario you can set `to="."` which will give you access to loosely typed search params.
+In this scenario you can set `to="."` which will give you access to loosely typed search params.
Here is an example that illustrates this:
```tsx
diff --git a/docs/router/how-to/setup-basic-search-params.md b/docs/router/how-to/setup-basic-search-params.md
index 8c9cbbe2e8b..27e49f7584a 100644
--- a/docs/router/how-to/setup-basic-search-params.md
+++ b/docs/router/how-to/setup-basic-search-params.md
@@ -10,7 +10,6 @@ Set up search parameters with schema validation (recommended for production):
```tsx
import { createFileRoute } from '@tanstack/react-router'
-import { zodValidator, fallback } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
@@ -20,7 +19,7 @@ const productSearchSchema = z.object({
})
export const Route = createFileRoute('/products')({
- validateSearch: zodValidator(productSearchSchema),
+ validateSearch: productSearchSchema,
component: ProductsPage,
})
@@ -50,7 +49,25 @@ function ProductsPage() {
## Validation Library Setup
-TanStack Router supports any standard schema-compliant validation library. This guide focuses on Zod for examples, but you can use any validation library:
+TanStack Router supports any standard schema-compliant validation library. This guide focuses on Zod for examples, but you can use any validation library.
+
+Using Zod v4:
+
+```tsx
+import { z } from 'zod'
+
+const searchSchema = z.object({
+ page: z.number().default(1),
+ category: z.string().default('all').catch('all'),
+})
+
+export const Route = createFileRoute('/products')({
+ validateSearch: searchSchema,
+ component: ProductsPage,
+})
+```
+
+For Zod v3:
```bash
npm install zod @tanstack/zod-adapter
@@ -75,15 +92,9 @@ export const Route = createFileRoute('/products')({
## Step-by-Step Setup with Zod
-The rest of this guide uses Zod for examples, but the patterns apply to any validation library.
+The rest of this guide uses Zod v4 for examples, but the patterns apply to any validation library.
-### Step 1: Install Dependencies
-
-```bash
-npm install zod @tanstack/zod-adapter
-```
-
-### Step 2: Define Your Search Schema
+### Step 1: Define Your Search Schema
Start by identifying what search parameters your route needs:
@@ -93,40 +104,38 @@ import { fallback } from '@tanstack/zod-adapter'
const shopSearchSchema = z.object({
// Pagination
- page: fallback(z.number(), 1).default(1),
- limit: fallback(z.number(), 20).default(20),
+ page: z.number().default(1),
+ limit: z.number().default(20),
// Filtering
- category: fallback(z.string(), 'all').default('all'),
- minPrice: fallback(z.number(), 0).default(0),
- maxPrice: fallback(z.number(), 1000).default(1000),
+ category: z.string().default('all'),
+ minPrice: z.number().default(0),
+ maxPrice: z.number().default(1000),
// Settings
- sort: fallback(z.enum(['name', 'price', 'date']), 'name').default('name'),
- ascending: fallback(z.boolean(), true).default(true),
+ sort: z.enum(['name', 'price', 'date']).default('name'),
+ ascending: z.boolean().default(true),
// Optional parameters
searchTerm: z.string().optional(),
- showOnlyInStock: fallback(z.boolean(), false).default(false),
+ showOnlyInStock: z.boolean().default(false),
})
type ShopSearch = z.infer
```
-### Step 3: Add Schema Validation to Route
+### Step 2: Add Schema Validation to Route
-Use the validation adapter to connect your schema to the route:
+Connect your schema to the route:
```tsx
-import { zodValidator } from '@tanstack/zod-adapter'
-
export const Route = createFileRoute('/shop')({
- validateSearch: zodValidator(shopSearchSchema),
+ validateSearch: shopSearchSchema,
component: ShopPage,
})
```
-### Step 4: Read Search Parameters in Components
+### Step 3: Read Search Parameters in Components
Use the route's `useSearch()` hook to access validated and typed search parameters:
@@ -166,12 +175,12 @@ function ShopPage() {
```tsx
const paginationSchema = z.object({
- page: fallback(z.number().min(1), 1).default(1),
- limit: fallback(z.number().min(10).max(100), 20).default(20),
+ page: z.number().min(1).default(1),
+ limit: z.number().min(10).max(100).default(20),
})
export const Route = createFileRoute('/posts')({
- validateSearch: zodValidator(paginationSchema),
+ validateSearch: paginationSchema,
component: PostsPage,
})
@@ -196,16 +205,13 @@ function PostsPage() {
```tsx
const catalogSchema = z.object({
- sort: fallback(z.enum(['name', 'date', 'price']), 'name').default('name'),
- category: fallback(
- z.enum(['electronics', 'clothing', 'books', 'all']),
- 'all',
- ).default('all'),
- ascending: fallback(z.boolean(), true).default(true),
+ sort: z.enum(['name', 'date', 'price']).default('name'),
+ category: z.enum(['electronics', 'clothing', 'books', 'all']).default('all'),
+ ascending: z.boolean().default(true),
})
export const Route = createFileRoute('/catalog')({
- validateSearch: zodValidator(catalogSchema),
+ validateSearch: catalogSchema,
component: CatalogPage,
})
```
@@ -215,27 +221,24 @@ export const Route = createFileRoute('/catalog')({
```tsx
const dashboardSchema = z.object({
// Numbers with validation
- userId: fallback(z.number().positive(), 1).default(1),
- refreshInterval: fallback(z.number().min(1000).max(60000), 5000).default(
- 5000,
- ),
+ userId: z.number().positive().default(1),
+ refreshInterval: z.number().min(1000).max(60000).default(5000),
// Strings with validation
- theme: fallback(z.enum(['light', 'dark']), 'light').default('light'),
+ theme: z.enum(['light', 'dark']).default('light'),
timezone: z.string().optional(),
// Arrays with validation
- selectedIds: fallback(z.number().array(), []).default([]),
- tags: fallback(z.string().array(), []).default([]),
+ selectedIds: z.number().array().default([]),
+ tags: z.string().array().default([]),
// Objects with validation
- filters: fallback(
- z.object({
+ filters: z
+ .object({
status: z.enum(['active', 'inactive']).optional(),
type: z.string().optional(),
- }),
- {},
- ).default({}),
+ })
+ .default({}),
})
```
@@ -245,8 +248,8 @@ const dashboardSchema = z.object({
const reportSchema = z.object({
startDate: z.string().pipe(z.coerce.date()).optional(),
endDate: z.string().pipe(z.coerce.date()).optional(),
- format: fallback(z.enum(['pdf', 'csv', 'excel']), 'pdf').default('pdf'),
- includeCharts: fallback(z.boolean(), true).default(true),
+ format: z.enum(['pdf', 'csv', 'excel']).default('pdf').catch('pdf'),
+ includeCharts: z.boolean().default(true),
})
```
@@ -330,7 +333,7 @@ export const Route = createFileRoute('/example')({
### Problem: Search Parameters Cause TypeScript Errors
-**Cause:** Missing or incorrect schema definition.
+**Cause:** Missing or incorrect schema definition with Zod v3.
**Solution:** Ensure your schema covers all search parameters and use proper types:
@@ -366,7 +369,7 @@ const schema = z.object({
// ✅ Graceful fallback handling
const schema = z.object({
- page: fallback(z.number(), 1).default(1), // Safe fallback to 1
+ page: z.number().default(1).catch(1), // Safe fallback to 1
})
```
diff --git a/docs/router/how-to/share-search-params-across-routes.md b/docs/router/how-to/share-search-params-across-routes.md
index 145d1f089b3..e1e24c1e0d1 100644
--- a/docs/router/how-to/share-search-params-across-routes.md
+++ b/docs/router/how-to/share-search-params-across-routes.md
@@ -21,7 +21,6 @@ Share parameters across your entire application by validating them in the root r
```tsx
// routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const globalSearchSchema = z.object({
@@ -31,7 +30,7 @@ const globalSearchSchema = z.object({
})
export const Route = createRootRoute({
- validateSearch: zodValidator(globalSearchSchema),
+ validateSearch: globalSearchSchema,
component: RootComponent,
})
@@ -50,7 +49,6 @@ function RootComponent() {
```tsx
// routes/products/index.tsx
import { createFileRoute } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
@@ -59,7 +57,7 @@ const productSearchSchema = z.object({
})
export const Route = createFileRoute('/products/')({
- validateSearch: zodValidator(productSearchSchema),
+ validateSearch: productSearchSchema,
component: ProductsPage,
})
@@ -84,7 +82,6 @@ Share parameters within a section of your app using layout routes:
```tsx
// routes/_authenticated.tsx
import { createFileRoute, Outlet } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const authSearchSchema = z.object({
@@ -94,7 +91,7 @@ const authSearchSchema = z.object({
})
export const Route = createFileRoute('/_authenticated')({
- validateSearch: zodValidator(authSearchSchema),
+ validateSearch: authSearchSchema,
component: AuthenticatedLayout,
})
@@ -181,7 +178,7 @@ function ProductsPage() {
```tsx
// ✅ Root route validates shared parameters
export const Route = createRootRoute({
- validateSearch: zodValidator(globalSearchSchema),
+ validateSearch: globalSearchSchema,
component: RootComponent,
})
```
diff --git a/docs/router/how-to/validate-search-params.md b/docs/router/how-to/validate-search-params.md
index bb141a5a196..5abd435cef8 100644
--- a/docs/router/how-to/validate-search-params.md
+++ b/docs/router/how-to/validate-search-params.md
@@ -12,15 +12,14 @@ Add robust validation with custom error messages, complex types, and production-
```tsx
import { createFileRoute, useRouter } from '@tanstack/react-router'
-import { zodValidator, fallback } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
query: z.string().min(1, 'Search query required'),
category: z.enum(['electronics', 'clothing', 'books', 'home']).optional(),
- minPrice: fallback(z.number().min(0, 'Price cannot be negative'), 0),
- maxPrice: fallback(z.number().min(0, 'Price cannot be negative'), 1000),
- inStock: fallback(z.boolean(), true),
+ minPrice: z.number().min(0, 'Price cannot be negative').default(0),
+ maxPrice: z.number().min(0, 'Price cannot be negative').default(1000),
+ inStock: z.boolean().default(true),
tags: z.array(z.string()).optional(),
dateRange: z
.object({
@@ -31,7 +30,7 @@ const productSearchSchema = z.object({
})
export const Route = createFileRoute('/products')({
- validateSearch: zodValidator(productSearchSchema),
+ validateSearch: productSearchSchema,
errorComponent: ({ error }) => {
const router = useRouter()
return (
@@ -80,7 +79,7 @@ TanStack Router supports multiple validation libraries through adapters:
### Zod (Recommended)
-Most popular with excellent TypeScript integration:
+Most popular with excellent TypeScript integration. For Zod v3, use `@tanstack/zod-adapter` for validation:
```tsx
import { zodValidator, fallback } from '@tanstack/zod-adapter'
@@ -99,6 +98,24 @@ export const Route = createFileRoute('/search')({
})
```
+For Zod v4, the adapter is no longer necessary:
+
+```tsx
+import { z } from 'zod'
+
+const searchSchema = z.object({
+ query: z.string().min(1).max(100),
+ page: z.number().int().positive().default(1),
+ sortBy: z.enum(['name', 'date', 'relevance']).optional(),
+ filters: z.array(z.string()).optional(),
+})
+
+export const Route = createFileRoute('/search')({
+ validateSearch: searchSchema,
+ component: SearchPage,
+})
+```
+
### Valibot
Lightweight alternative with modular design:
diff --git a/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md b/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
index 602c49a7a65..c9f53358e6f 100644
--- a/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
+++ b/packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
@@ -243,14 +243,11 @@ TanStack Router:
// In the route definition:
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
-import { zodValidator, fallback } from '@tanstack/zod-adapter'
export const Route = createFileRoute('/posts')({
- validateSearch: zodValidator(
- z.object({
- page: fallback(z.number(), 1).default(1),
- }),
- ),
+ validateSearch: z.object({
+ page: z.number().default(1).catch(1),
+ }),
component: Posts,
})
@@ -441,11 +438,10 @@ const page = Number(searchParams.get('page'))
// CORRECT — TanStack Router pattern, returns typed object
// Route definition:
-validateSearch: zodValidator(
+validateSearch:
z.object({
- page: fallback(z.number(), 1).default(1),
+ page: z.number().default(1).catch(1),
}),
-)
// Component:
const { page } = Route.useSearch()
diff --git a/packages/router-core/skills/router-core/search-params/SKILL.md b/packages/router-core/skills/router-core/search-params/SKILL.md
index d714969416d..5f294afdf90 100644
--- a/packages/router-core/skills/router-core/search-params/SKILL.md
+++ b/packages/router-core/skills/router-core/search-params/SKILL.md
@@ -23,7 +23,7 @@ sources:
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()`, 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).
+> **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)
@@ -35,19 +35,18 @@ npm install zod @tanstack/zod-adapter
```tsx
// src/routes/products.tsx
import { createFileRoute } from '@tanstack/react-router'
-import { zodValidator, fallback } from '@tanstack/zod-adapter'
import { z } from 'zod'
const productSearchSchema = z.object({
- page: fallback(z.number(), 1).default(1),
- filter: fallback(z.string(), '').default(''),
- sort: fallback(z.enum(['newest', 'oldest', 'price']), 'newest').default(
+ 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: zodValidator(productSearchSchema),
+ validateSearch: productSearchSchema,
component: ProductsPage,
})
@@ -168,15 +167,14 @@ Parent route search params are automatically merged into child routes:
```tsx
// src/routes/shop.tsx — parent defines shared params
import { createFileRoute } from '@tanstack/react-router'
-import { zodValidator, fallback } from '@tanstack/zod-adapter'
import { z } from 'zod'
const shopSearchSchema = z.object({
- currency: fallback(z.enum(['USD', 'EUR']), 'USD').default('USD'),
+ currency: z.enum(['USD', 'EUR']).default('USD').catch('USD'),
})
export const Route = createFileRoute('/shop')({
- validateSearch: zodValidator(shopSearchSchema),
+ validateSearch: shopSearchSchema,
})
```
@@ -201,7 +199,6 @@ function ShopProducts() {
```tsx
import { createRootRoute, retainSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const rootSearchSchema = z.object({
@@ -209,7 +206,7 @@ const rootSearchSchema = z.object({
})
export const Route = createRootRoute({
- validateSearch: zodValidator(rootSearchSchema),
+ validateSearch: rootSearchSchema,
search: {
middlewares: [retainSearchParams(['debug'])],
},
@@ -220,7 +217,6 @@ export const Route = createRootRoute({
```tsx
import { createFileRoute, stripSearchParams } from '@tanstack/react-router'
-import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const defaults = { sort: 'newest', page: 1 }
@@ -231,7 +227,7 @@ const searchSchema = z.object({
})
export const Route = createFileRoute('/items')({
- validateSearch: zodValidator(searchSchema),
+ validateSearch: searchSchema,
search: {
middlewares: [stripSearchParams(defaults)],
},
@@ -242,13 +238,11 @@ export const Route = createFileRoute('/items')({
```tsx
export const Route = createFileRoute('/search')({
- validateSearch: zodValidator(
- z.object({
- retainMe: z.string().optional(),
- arrayWithDefaults: z.string().array().default(['foo', 'bar']),
- required: z.string(),
- }),
- ),
+ validateSearch: z.object({
+ retainMe: z.string().optional(),
+ arrayWithDefaults: z.string().array().default(['foo', 'bar']),
+ required: z.string(),
+ }),
search: {
middlewares: [
retainSearchParams(['retainMe']),
@@ -281,7 +275,7 @@ const router = createRouter({
```tsx
export const Route = createFileRoute('/products')({
- validateSearch: zodValidator(productSearchSchema),
+ validateSearch: productSearchSchema,
// Pick ONLY the params the loader needs — not the entire search object
loaderDeps: ({ search }) => ({ page: search.page }),
loader: async ({ deps }) => {
@@ -292,7 +286,7 @@ export const Route = createFileRoute('/products')({
## Common Mistakes
-### 1. HIGH: Using zod `.catch()` with `zodValidator()` instead of adapter `fallback()`
+### 1. HIGH: Using zod v3's `.catch()` with `zodValidator()` instead of adapter `fallback()`
```tsx
// WRONG — .catch() with zodValidator makes the type unknown
@@ -304,6 +298,8 @@ import { fallback } from '@tanstack/zod-adapter'
const schema = z.object({ page: fallback(z.number(), 1) })
```
+**Important:** This only applies when using Zod v3, not when using Zod v4. For v4, using `.catch()` is correct.
+
### 2. HIGH: Returning entire search object from `loaderDeps`
```tsx
@@ -335,7 +331,7 @@ export const Route = createRootRoute({
// CORRECT — parent must define validateSearch for children to inherit
export const Route = createRootRoute({
- validateSearch: zodValidator(globalSearchSchema),
+ validateSearch: globalSearchSchema,
component: RootComponent,
})
```