Create your own
Lesson illustration

Typed Routes with Path and Search Parameters

Hello! Welcome back to your course on mastering TanStack Start and Router.

In our last lesson, we compared the file-based routing conventions of TanStack Router with the Next.js App Router. You learned how TanStack uses a hybrid approach, generating a typed route tree from your file system, and we explored conventions for creating basic routes, layouts, and dynamic segments.

Lesson 4: Typed Route Definitions

Today's Goal:

This lesson directly addresses the learning outcome: Create typed route definitions with path parameters and search params. We'll move beyond just defining the structure of our routes and start working with the dynamic data embedded within the URL. This is where TanStack Router's emphasis on type safety really begins to shine.

As someone with extensive experience in front-end development, you know that managing state from the URL can be error-prone. Today, you'll see how TanStack Router turns URL parameters into a reliable, type-safe source of application state.

What we will cover:

  1. Typed Path Parameters: Defining and accessing dynamic URL segments like a post ID.
  2. Typed Search Parameters: Validating and consuming query string values like filters or page numbers.
  3. Validation with Zod: Using schema validation to create robust and self-documenting search parameter definitions.

1. Typed Path Parameters

Path parameters are dynamic segments of a URL path. For example, in /posts/123, 123 is a path parameter representing a specific post's ID.

In the previous lesson, you saw that the convention for this is a filename prefixed with a dollar sign, like src/routes/posts/$postId.tsx. Let's explore how TanStack Router makes this type-safe.

Defining and Accessing Path Params

When you create a file like src/routes/posts/$postId.tsx, the router automatically infers that any navigation to this route must include a postId parameter. It also makes this parameter available to your component and its associated functions in a fully typed manner.

  • In Components: You can access path parameters using the Route.useParams() hook.
  • In Loaders: Path parameters are passed directly to the loader function via its params property. This is the most common use case, as you'll typically use the parameter to fetch data for the page.

The official documentation provides a clear, concise reference for these concepts.

Path Params | TanStack Router React Docs

Please read the official documentation on Path Params. It's a quick read that will solidify your understanding of the core concepts.

Read the sections 'Path Params', 'Path Params in Loaders', and 'Path Params in Components'. Focus on the $postId syntax and how the params object is accessed in both loaders and components.

Let's see a practical demonstration. The following video segment builds out a nested contact page, showing how path parameters for country and city are defined and used to fetch and display data.

Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing

This video demonstrates how to create routes with path parameters and access them within your loader and component to fetch and render data. It's a great practical example of the concepts from the documentation.

Watch the segment from 25:28 to 34:21. Pay close attention to how the $country and $city routes are created and how the params object is used in the loader function and for creating Link components.

Optional Path Parameters

Sometimes, a parameter might not be required. A common example is for internationalization (i18n), where a language code might be present in the URL (/en/blog) but is optional for the default language (/blog). TanStack Router handles this with a specific file-naming convention: {-$paramName}.

For example, a file named src/routes/{-$lang}/blog.tsx would match both /en/blog and /blog. Inside your component or loader, the lang parameter would be typed as string | undefined.

The documentation covers this feature, which is useful for building flexible and realistic applications.

Path Params | TanStack Router React Docs

Now, let's look at the documentation for optional path parameters. This is a powerful feature for scenarios like i18n.

Read the sections 'Optional Path Parameters' and 'Type Safety with Optional Parameters'. Note the {-$paramName} syntax and how TypeScript correctly infers the parameter as potentially undefined.


2. Typed Search Parameters

Search parameters (or query strings) are the key-value pairs in a URL that appear after the ?, like ?sort=desc&page=2. They are an excellent tool for managing UI state that should be bookmarkable and shareable, such as filters, sorting, and pagination.

However, search params are inherently just strings and represent untrusted user input. A user could easily change ?page=2 to ?page=hello, which could crash your application if not handled correctly.

TanStack Router solves this with a powerful validation system.

Validation with validateSearch and Zod

Every route definition can include a validateSearch option. This function receives the raw, parsed search params from the URL and is responsible for returning a clean, typed, and validated object.

While you can write this validation logic by hand, the recommended approach is to use a schema validation library like Zod. TanStack Router has first-class support for it.

Here's the workflow:

  1. Define a Zod schema that describes the expected shape, types, and default values for your search parameters.
  2. Pass this schema directly to the validateSearch option of your route.
  3. The router handles the rest, ensuring that any access to the search params within your app is fully typed and safe.

This is a cornerstone of building robust applications with TanStack Router. The official documentation provides an in-depth guide.

Search Params | TanStack Router React Docs

Please read the documentation on Search Params. This is a critical feature of the router. Focus on the 'why' behind URL state and the mechanics of validation.

Read the sections 'Search Params, the "OG" State Manager', 'Validating and Typing Search Params', and the sub-section on 'Zod'. This explains the philosophy and the practical implementation with a validation library.

Accessing Search Params

Once validated, you can access the search parameters in a type-safe way:

  • In Components: Use the Route.useSearch() hook. It returns the object you defined in your Zod schema.
  • In Loaders: Unlike path params, search params must be explicitly passed to loaders via the loaderDeps option. This ensures the loader re-runs only when the search params it depends on have changed.

The following video provides a fantastic walkthrough of implementing a search page with complex filters, using Zod for validation and accessing the typed params in the loader.

Complete TanStack Router Tutorial - Build Type-Safe React Apps with File-Based Routing

This segment demonstrates a real-world use case for search parameters: a filterable search page. It shows exactly how to integrate a Zod schema to achieve end-to-end type safety.

Watch from 46:55 to 51:32. Observe how the searchSchema is created with Zod, passed to validateSearch, and how the loaderDeps option is used to make the validated search object available to the loader function.


3. Practical Example: Tying It All Together

Let's solidify these concepts with a concrete example. Imagine a route for viewing a specific product, with an optional tab for showing reviews.

URL: /products/abc-123?tab=reviews

  • Path Parameter: productId (abc-123)
  • Search Parameter: tab (reviews)

Here’s how you would define this route in src/routes/products/$productId.tsx:

import { createFileRoute } from '@tanstack/react-router';
import { z } from 'zod';

// 1. Define the Zod schema for search params
const productSearchSchema = z.object({
  // 'tab' is a string, which can be one of two values, and defaults to 'details'
  tab: z.enum(['details', 'reviews']).default('details').catch('details'),
});

export const Route = createFileRoute('/products/$productId')({
  // 2. Use the schema to validate search params
  validateSearch: productSearchSchema,

  // 3. Define the component
  component: ProductComponent,
});

function ProductComponent() {
  // 4. Access the typed path and search params
  const { productId } = Route.useParams(); // TypeScript knows this is a string
  const { tab } = Route.useSearch(); // TypeScript knows this is 'details' | 'reviews'

  return (
    <div>
      <h1>Product ID: {productId}</h1>
      <p>Current Tab: {tab}</p>
      
      {/* Render content based on the tab */}
      {tab === 'details' && <div>Showing product details...</div>}
      {tab === 'reviews' && <div>Showing product reviews...</div>}
    </div>
  );
}

In this example:

  • useParams() gives you productId as a string.
  • useSearch() gives you tab as either 'details' or 'reviews', guaranteed by the Zod schema.
  • If the tab param is missing or invalid in the URL, it safely defaults to 'details'. This prevents runtime errors and creates a more resilient user experience.

Conclusion

Today you've learned how to harness the URL to manage application state in a fully type-safe way using TanStack Router. This is a fundamental skill for building the complex, data-driven applications you're aiming for.

Key Takeaways:

  • Path Parameters: Defined with $ in filenames (e.g., $postId.tsx) and accessed via Route.useParams(). They are automatically typed as strings.
  • Search Parameters: Validated using the validateSearch route option, ideally with a Zod schema for robustness and clarity.
  • Accessing Params: Use Route.useParams() for path params and Route.useSearch() for search params in components. In loaders, path params are on the params object, while search params require the loaderDeps option.
  • Type Safety is Key: This entire system is designed to catch errors at compile time and prevent runtime failures from malformed URLs.

Next Lesson Preview:

Now that you know how to define routes that accept typed parameters, the next logical step is to learn how to navigate to them. In our next lesson, we will "Implement typed navigation using the Link component and useNavigate hook." You'll see how the schemas and route definitions you created today enable TypeScript to provide autocompletion and error-checking when you create links, ensuring you can't navigate to an invalid URL.

Can't find a good explanation? Sign up and we'll make it for you

Sign up