Docs: Update search parameters guide for zod v4#6956
Docs: Update search parameters guide for zod v4#6956robballou wants to merge 4 commits intoTanStack:mainfrom
Conversation
Zod v4 does not require use of the adapter and can use the schemas directly. See TanStack#4322
📝 WalkthroughWalkthroughDocumentation updated to replace zod-adapter wrapper usage with direct Zod v4 schema examples for validateSearch while retaining adapter guidance for Zod v3. Examples, notes, and schemas across guides, API docs, how-tos, and migration skills now show validateSearch accepting raw Zod schemas and clarify .catch/.default vs fallback differences. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Additional question, there are 12 other files which mention the |
@robballou Yes, that would be good to get everything modernized. |
Bundle Size Benchmarks
Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better. |
|
View your CI Pipeline Execution ↗ for commit 0451f0d
☁️ Nx Cloud last updated this comment at |
|
I have updated more of the documentation while hopefully retaining the value. I am trying to give both v3 and v4 examples where it seems appropriate. In a few places, I replaced the instructions with Zod v4 only as it seems new projects would use v4. Notes:
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/router/how-to/setup-basic-search-params.md (2)
103-103: 🛠️ Refactor suggestion | 🟠 MajorRemove unused
fallbackimport after v4 migration.Line 103 imports
fallbackfrom@tanstack/zod-adapter, but after the v4 updates, all examples in this section now use.default()instead offallback(). This import is no longer used and should be removed to avoid confusion.🧹 Proposed fix to remove unused import
import { z } from 'zod' -import { fallback } from '@tanstack/zod-adapter'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/router/how-to/setup-basic-search-params.md` at line 103, Remove the now-unused fallback import from `@tanstack/zod-adapter`: delete the import statement that includes "fallback" (the line "import { fallback } from '@tanstack/zod-adapter'") and verify examples in this document use .default() instead—ensure there are no remaining references to the fallback symbol in the section so the import can be fully removed.
15-22:⚠️ Potential issue | 🟠 MajorQuick start example mixes Zod v3 and v4 patterns inconsistently.
The schema definition (lines 15-19) uses
fallback()from the Zod adapter:page: fallback(z.number(), 1).default(1), category: fallback(z.string(), 'all').default('all'), showSale: fallback(z.boolean(), false).default(false),But line 22 uses the schema directly without the adapter wrapper:
validateSearch: productSearchSchema, // No zodValidator() wrapperThis combination won't work because:
fallback()requires@tanstack/zod-adapterto be installed- Users following the v4 guidance won't have the adapter package
- The pattern contradicts the v4 examples shown later (lines 54-68)
🔄 Proposed fix to use pure Zod v4 syntax
const productSearchSchema = z.object({ - page: fallback(z.number(), 1).default(1), - category: fallback(z.string(), 'all').default('all'), - showSale: fallback(z.boolean(), false).default(false), + page: z.number().default(1), + category: z.string().default('all'), + showSale: z.boolean().default(false), })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/router/how-to/setup-basic-search-params.md` around lines 15 - 22, The example mixes the Zod adapter's fallback() with an unwrapped schema; replace fallback(...) usages in productSearchSchema with pure Zod v4 forms (e.g., z.coerce.number().default(1), z.coerce.string().default('all'), z.coerce.boolean().default(false)) so the schema is standalone, and then pass it into createFileRoute using the zodValidator wrapper (validateSearch: zodValidator(productSearchSchema)) to match v4 patterns and remove the dependency on `@tanstack/zod-adapter`.
🧹 Nitpick comments (1)
docs/router/how-to/validate-search-params.md (1)
220-222: Consider adding version labels tofallback()examples.Several code examples throughout the guide continue using the
fallback()helper (lines 220, 341, 421, 434, 538, 576) without indicating whether they're Zod v3 or v4 examples. Since the quick start and dedicated sections now clearly distinguish v3 vs v4, these examples may confuse users about which pattern to follow.Consider either:
- Converting these to Zod v4 syntax (
.default()and.catch())- Adding comments like
// Zod v3 patternwherefallback()is used- Providing both v3 and v4 versions in these pattern sections
Also applies to: 340-346, 421-423, 538-539, 576-577
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/router/how-to/validate-search-params.md` around lines 220 - 222, The docs use the Zod helper fallback() in multiple examples (e.g., the page: fallback(...), limit: fallback(...)) without indicating whether these are Zod v3 or v4 patterns; update those examples by either converting them to Zod v4 equivalents using .default() and .catch(), or add inline comments like "// Zod v3 pattern" next to fallback() usages, or provide both versions side-by-side so readers can see fallback() (v3) and the .default()/.catch() (v4) alternatives; apply this change consistently for all occurrences of fallback() in these examples to avoid ambiguity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/router-core/skills/router-core/search-params/SKILL.md`:
- Around line 49-50: The code example is missing the fallback import used by
fallback() in the snippet; update the example's imports to include fallback
(e.g., add an import for fallback alongside other imports) so the call to
fallback() used with validateSearch, productSearchSchema, and component:
ProductsPage resolves correctly; ensure the imported symbol name is exactly
fallback to match its usage in the example.
---
Outside diff comments:
In `@docs/router/how-to/setup-basic-search-params.md`:
- Line 103: Remove the now-unused fallback import from `@tanstack/zod-adapter`:
delete the import statement that includes "fallback" (the line "import {
fallback } from '@tanstack/zod-adapter'") and verify examples in this document
use .default() instead—ensure there are no remaining references to the fallback
symbol in the section so the import can be fully removed.
- Around line 15-22: The example mixes the Zod adapter's fallback() with an
unwrapped schema; replace fallback(...) usages in productSearchSchema with pure
Zod v4 forms (e.g., z.coerce.number().default(1),
z.coerce.string().default('all'), z.coerce.boolean().default(false)) so the
schema is standalone, and then pass it into createFileRoute using the
zodValidator wrapper (validateSearch: zodValidator(productSearchSchema)) to
match v4 patterns and remove the dependency on `@tanstack/zod-adapter`.
---
Nitpick comments:
In `@docs/router/how-to/validate-search-params.md`:
- Around line 220-222: The docs use the Zod helper fallback() in multiple
examples (e.g., the page: fallback(...), limit: fallback(...)) without
indicating whether these are Zod v3 or v4 patterns; update those examples by
either converting them to Zod v4 equivalents using .default() and .catch(), or
add inline comments like "// Zod v3 pattern" next to fallback() usages, or
provide both versions side-by-side so readers can see fallback() (v3) and the
.default()/.catch() (v4) alternatives; apply this change consistently for all
occurrences of fallback() in these examples to avoid ambiguity.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 09ff36d7-7b3b-416a-bee9-8f183d8eccd3
📒 Files selected for processing (7)
docs/router/api/router/retainSearchParamsFunction.mddocs/router/api/router/stripSearchParamsFunction.mddocs/router/how-to/setup-basic-search-params.mddocs/router/how-to/share-search-params-across-routes.mddocs/router/how-to/validate-search-params.mdpackages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.mdpackages/router-core/skills/router-core/search-params/SKILL.md
| validateSearch: productSearchSchema, | ||
| component: ProductsPage, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify markdown code blocks that call fallback(...) without importing it.
python - <<'PY'
import re, pathlib
targets = [
pathlib.Path("packages/router-core/skills/router-core/search-params/SKILL.md"),
pathlib.Path("packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md"),
]
fence_re = re.compile(r"```(?:tsx|ts|js|jsx|python|bash)?\n(.*?)\n```", re.S)
for p in targets:
text = p.read_text(encoding="utf-8")
blocks = fence_re.findall(text)
for i, b in enumerate(blocks, 1):
if "fallback(" in b and "@tanstack/zod-adapter" not in b:
print(f"{p} :: code block #{i} uses fallback(...) without adapter import")
PYRepository: TanStack/router
Length of output: 180
🏁 Script executed:
# Read the file to see the code block context and verify line numbers
head -60 packages/router-core/skills/router-core/search-params/SKILL.md | tail -30Repository: TanStack/router
Length of output: 794
🏁 Script executed:
# Check if fallback is exported from `@tanstack/zod-adapter`
fd -e ts -e js "zod-adapter" packages/ | head -5Repository: TanStack/router
Length of output: 41
🏁 Script executed:
# Search for zod-adapter references in the codebase
rg "@tanstack/zod-adapter" --type md -A 2 | head -20Repository: TanStack/router
Length of output: 1739
Add missing fallback import to the code example.
The code block uses fallback() on lines 41–43 but doesn't import it. The import statement is missing:
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
+import { fallback } from '@tanstack/zod-adapter'This import appears correctly in another example in the same file; it needs to be added here for the code snippet to be functional when copied.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/router-core/skills/router-core/search-params/SKILL.md` around lines
49 - 50, The code example is missing the fallback import used by fallback() in
the snippet; update the example's imports to include fallback (e.g., add an
import for fallback alongside other imports) so the call to fallback() used with
validateSearch, productSearchSchema, and component: ProductsPage resolves
correctly; ensure the imported symbol name is exactly fallback to match its
usage in the example.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/router/how-to/setup-basic-search-params.md (1)
11-19:⚠️ Potential issue | 🟠 MajorQuick Start snippet is non-runnable:
fallback()is used without being imported.The Quick Start code at lines 11-19 references
fallback()but imports onlyzfromzod. Later sections in the file promote Zod v4 direct schema validation. Update this snippet to use native Zod v4 syntax (.default()and.catch()) so users can copy and run it immediately.Proposed fix (align with Zod v4 native approach)
import { createFileRoute } from '@tanstack/react-router' import { z } from 'zod' const productSearchSchema = z.object({ - page: fallback(z.number(), 1).default(1), - category: fallback(z.string(), 'all').default('all'), - showSale: fallback(z.boolean(), false).default(false), + page: z.number().default(1).catch(1), + category: z.string().default('all').catch('all'), + showSale: z.boolean().default(false).catch(false), })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/router/how-to/setup-basic-search-params.md` around lines 11 - 19, The snippet uses the non-imported fallback() helper in productSearchSchema; replace those calls with native Zod v4 patterns so the snippet is runnable — for example change page: fallback(z.number(), 1).default(1) to page: z.number().catch(1).default(1), category: fallback(z.string(), 'all').default('all') to category: z.string().catch('all').default('all'), and showSale: fallback(z.boolean(), false).default(false) to showSale: z.boolean().catch(false).default(false); keep the existing import of z from 'zod' and update only the productSearchSchema definition.
♻️ Duplicate comments (1)
packages/router-core/skills/router-core/search-params/SKILL.md (1)
35-43:⚠️ Potential issue | 🟠 MajorAdapter setup example is still broken and mixed-mode (duplicate of prior finding).
This snippet still uses
fallback(...)without importing it, and the section title says “Zod Adapter (Recommended)” while the route uses direct schema assignment. Please make the example consistently adapter-based or rename/rewrite it as v4 direct-schema guidance.If keeping this section adapter-based, use this fix
// src/routes/products.tsx import { createFileRoute } from '@tanstack/react-router' import { z } from 'zod' +import { fallback, zodValidator } from '@tanstack/zod-adapter' @@ export const Route = createFileRoute('/products')({ - validateSearch: productSearchSchema, + validateSearch: zodValidator(productSearchSchema), component: ProductsPage, })Also applies to: 49-49
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/router-core/skills/router-core/search-params/SKILL.md` around lines 35 - 43, The example under "Zod Adapter (Recommended)" is inconsistent: productSearchSchema uses fallback(...) without importing it and the route uses a direct schema instead of the adapter; fix by either (A) making this a proper adapter example—rename the section if you want to keep direct schema, or rewrite the snippet to use the Zod search-params adapter API and pass a zod schema through that adapter (replace direct usage of productSearchSchema in createFileRoute with the adapter-based call), or (B) if you intend to show the v4 direct-schema approach, remove the adapter title and import fallback (and any other helpers) so productSearchSchema compiles; ensure the symbols productSearchSchema, fallback, createFileRoute and any adapter helper you choose are present and used consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/router/how-to/setup-basic-search-params.md`:
- Line 95: Remove the unused `fallback` import from the Step 1 example: locate
the import that brings in the Zod v4 adapter and remove the `fallback` specifier
(or the entire adapter import if it only exported `fallback`), leaving only the
native Zod v4 usage that relies on `.default()`; ensure the example imports
exactly the symbols it uses so there are no unused imports.
---
Outside diff comments:
In `@docs/router/how-to/setup-basic-search-params.md`:
- Around line 11-19: The snippet uses the non-imported fallback() helper in
productSearchSchema; replace those calls with native Zod v4 patterns so the
snippet is runnable — for example change page: fallback(z.number(),
1).default(1) to page: z.number().catch(1).default(1), category:
fallback(z.string(), 'all').default('all') to category:
z.string().catch('all').default('all'), and showSale: fallback(z.boolean(),
false).default(false) to showSale: z.boolean().catch(false).default(false); keep
the existing import of z from 'zod' and update only the productSearchSchema
definition.
---
Duplicate comments:
In `@packages/router-core/skills/router-core/search-params/SKILL.md`:
- Around line 35-43: The example under "Zod Adapter (Recommended)" is
inconsistent: productSearchSchema uses fallback(...) without importing it and
the route uses a direct schema instead of the adapter; fix by either (A) making
this a proper adapter example—rename the section if you want to keep direct
schema, or rewrite the snippet to use the Zod search-params adapter API and pass
a zod schema through that adapter (replace direct usage of productSearchSchema
in createFileRoute with the adapter-based call), or (B) if you intend to show
the v4 direct-schema approach, remove the adapter title and import fallback (and
any other helpers) so productSearchSchema compiles; ensure the symbols
productSearchSchema, fallback, createFileRoute and any adapter helper you choose
are present and used consistently.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e7dc78b3-797a-4111-a8bb-fde236bde6e8
📒 Files selected for processing (3)
docs/router/how-to/setup-basic-search-params.mdpackages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.mdpackages/router-core/skills/router-core/search-params/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/react-router/skills/lifecycle/migrate-from-react-router/SKILL.md
| ## 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. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n docs/router/how-to/setup-basic-search-params.md | head -120 | tail -40Repository: TanStack/router
Length of output: 1472
🏁 Script executed:
cat -n docs/router/how-to/setup-basic-search-params.md | sed -n '120,180p'Repository: TanStack/router
Length of output: 1789
🏁 Script executed:
cat -n docs/router/how-to/setup-basic-search-params.md | sed -n '180,250p'Repository: TanStack/router
Length of output: 2176
🏁 Script executed:
cat -n docs/router/how-to/setup-basic-search-params.md | sed -n '250,350p'Repository: TanStack/router
Length of output: 3740
Remove unused fallback import from Step 1 example.
The Step 1 code imports the Zod v4 adapter but doesn't use it—the example correctly uses native Zod v4 .default() syntax instead. Remove the import to keep the example clean and consistent with the stated v4 approach.
Proposed fix
import { z } from 'zod'
-import { fallback } from '@tanstack/zod-adapter'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/router/how-to/setup-basic-search-params.md` at line 95, Remove the
unused `fallback` import from the Step 1 example: locate the import that brings
in the Zod v4 adapter and remove the `fallback` specifier (or the entire adapter
import if it only exported `fallback`), leaving only the native Zod v4 usage
that relies on `.default()`; ensure the example imports exactly the symbols it
uses so there are no unused imports.
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/router-core/skills/router-core/search-params/SKILL.md (1)
41-43: Section framing is inconsistent with the updated Zod v4 example.Lines 41–45 and Line 49 now correctly show Zod v4 direct-schema usage, but this section still reads as adapter-first setup. That contradiction can mislead readers on what to install/use first.
Suggested docs adjustment
-## Setup: Zod Adapter (Recommended) +## Setup: Zod v4 (Recommended) ```bash -npm install zod `@tanstack/zod-adapter` +npm install zod+For Zod v3 projects, use
@tanstack/zod-adapterwithzodValidator()andfallback().</details> Also applies to: 45-45, 49-49 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@packages/router-core/skills/router-core/search-params/SKILL.mdaround lines
41 - 43, Update the inconsistent docs section in SKILL.md to reflect Zod v4
usage by changing the install command to "npm install zod" and framing examples
as direct Zod v4 schema usage (e.g., z.number(), z.enum(), etc.); additionally
add a short note that projects still on Zod v3 should install and use
@tanstack/zod-adapterand the adapter helpers zodValidator() and fallback()
instead, ensuring the section consistently matches the examples elsewhere that
show direct-schema usage.</details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In@packages/router-core/skills/router-core/search-params/SKILL.md:
- Around line 41-43: Update the inconsistent docs section in SKILL.md to reflect
Zod v4 usage by changing the install command to "npm install zod" and framing
examples as direct Zod v4 schema usage (e.g., z.number(), z.enum(), etc.);
additionally add a short note that projects still on Zod v3 should install and
use@tanstack/zod-adapterand the adapter helpers zodValidator() and fallback()
instead, ensuring the section consistently matches the examples elsewhere that
show direct-schema usage.</details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `cb5d702b-05b5-4fcc-af5c-8f49790aef95` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 0451f0d2d58e2cfca015b63e52085cf37dc0262b and 5c7ffb5c56b64b3ab3cf3f8ebf098b80f0567031. </details> <details> <summary>📒 Files selected for processing (1)</summary> * `packages/router-core/skills/router-core/search-params/SKILL.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
Zod v4 does not require use of the adapter and can use the schemas directly. See #4322
Summary by CodeRabbit