Decide what belongs in the URL and give it stable defaults.
Search params are external input
Users can edit URLs and old bookmarks can contain stale data. Validate at the route boundary instead of scattering Number() calls through components.
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' : 'open',
}),
component: IssuesPage,
})
function IssuesPage() {
const filters = Route.useSearch()
return <p>Page {filters.page} · {filters.status}</p>
}What belongs in the URL
Filters, sorting, pagination, and selected tabs usually belong in the URL because users share, bookmark, navigate, and refresh them. Transient details like hover state do not.
Turn this lesson into a verifiable skill
Filters, status, and page restore from the URL, so refreshes and shared links preserve the view.
Add a priority filter with a default and omit that default when writing the URL.
An invalid page value should fall back safely, while a valid copied URL should reproduce the same filtered result.
- Using a TypeScript assertion without runtime validation.
- Accidentally clearing unrelated search parameters while updating one filter.