Capítulo 27 de 57

Chapter 27: Search Params

Core Idea

TanStack Router treats URL search params as first-class, JSON-typed application state (not raw URLSearchParams strings), providing automatic JSON serialization, a validateSearch step for typed/validated access, and composable middlewares to transform search params on every generated link.

Key Concepts

  • Why not URLSearchParams: It assumes flat string-only values, has no reliable nested-object/array support, and offers no validation layer; search params represent real app state (page number, filters) and deserve equivalent DX to other state managers, including referential integrity concerns.
  • JSON-first Parsing: Non-string first-level values (numbers, booleans) are preserved as their real type; nested objects/arrays are automatically JSON-encoded into the query string while staying URLSearchParams-compatible at the first level.
  • validateSearch: A Route option that takes the raw parsed Record<string, unknown> and returns a typed, validated object; this type flows to loader, beforeLoad, components, and is inherited by all child routes. Throwing inside validateSearch triggers the route's onError/errorComponent with error.routerCode === 'VALIDATE_SEARCH'.
  • Schema Library Adapters: Zod (zodValidator, fallback() for typed defaults in Zod v3; Zod v4 schemas can be used directly), Valibot, ArkType, and Effect/Schema all integrate via Standard Schema or a dedicated adapter, giving typed input/output shapes for navigation vs. reading.
  • Route.useSearch(): Reads validated search params inside the owning route's component.
  • useSearch({ from, strict: false }): Reads search params outside a route's own component; strict: false loosens typing to allow reading from any route context.
  • Search Param Inheritance: Search schemas merge down the route tree, a child route's beforeLoad/component sees its own plus all parent routes' validated search fields.
  • <Link search /> / navigate({ search }): Accept an object or an updater function (prev) => next to write search params; to="." combined with search={(prev) => ({...prev, ...})} updates search params without needing a typed from.
  • Search Middlewares: Functions of shape ({ search, next }) => result registered via search.middlewares on a route (commonly the root route) that transform search params whenever a link/href is built for that route or its descendants, and also run after search validation on navigation.
  • retainSearchParams(keys): Built-in middleware that always carries specified search keys through to newly generated links if present in current search.
  • stripSearchParams(defaults): Built-in middleware that omits search params from generated links when they equal their default value, keeping URLs clean.

Code Examples

import { z } from 'zod'

const productSearchSchema = z.object({
  page: z.number().catch(1),
  filter: z.string().catch(''),
  sort: z.enum(['newest', 'oldest', 'price']).catch('newest'),
})

export const Route = createFileRoute('/shop/products')({
  validateSearch: productSearchSchema,
})
  • What it demonstrates: Zod-based validateSearch using .catch() to silently fall back to defaults rather than erroring on malformed search params.
export const Route = createRootRoute({
  validateSearch: zodValidator(searchSchema),
  search: {
    middlewares: [retainSearchParams(['rootValue']), stripSearchParams(defaultValues)],
  },
})
  • What it demonstrates: Chaining built-in middlewares to retain some search params across all generated links while stripping others back to their defaults.

Key Takeaways

  1. Always validate search params with validateSearch (ideally via a schema library adapter) rather than trusting the raw parsed JSON, since search params originate as user-facing raw text.
  2. Prefer .catch()/fallback-style validation over .default()-only when a malformed search param shouldn't interrupt the user's experience with an error screen.
  3. Search middlewares (retainSearchParams, stripSearchParams, or custom ones) are the mechanism for cross-cutting search-param behavior (e.g. always keep a rootValue, always hide default-valued params) applied uniformly to every generated link.

Connects To

  • Ch 23: Navigation, the search field within ToOptions this chapter details.
  • Ch 26: Path Params, the equivalent typed-param mechanism for path segments rather than the query string.
  • Ch 28: Custom Search Param Serialization, replaces the default JSON parse/stringify behavior described here.