Execution contract
- Use when
- Use for filters, sorting, pagination, or shareable view state owned by the URL.
- Avoid when
- Do not store secrets, transient input, or large values that cannot be safely serialized.
- Preconditions
- Define allowed keys, runtime validation, defaults, and the canonical serialized URL shape.
- Verification
- Test valid, missing, and malformed values; refresh, back, and shared links must restore the same view.
- Failure mode
- If an update clears other keys, verify the search updater merges from previous state instead of returning a partial object.
- Security
- URL input is untrusted; successful parsing does not make it safe for SQL, file paths, or outbound requests.
Contract
validateSearch receives parsed but untrusted values. Its return value becomes the search type seen by loaders, Route.useSearch(), and child routes.
Implementation
Give invalid page values a stable default and constrain status to an explicit union.
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/issues/')({
validateSearch: (search: Record<string, unknown>) => ({
page: Math.max(1, Number(search.page) || 1),
status: search.status === 'closed' ? 'closed' as const : 'open' as const,
}),
component: IssuesPage,
})
function IssuesPage() {
const { page, status } = Route.useSearch()
return <p>{status} issues · page {page}</p>
}Common failures
Do not reparse search values in every component. Do not assume Number() yields a valid number. If the project already uses Zod or Valibot, reuse its existing schema.