Skip to content

Remix Params and Query — URL Parameters and Search Strings

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Remix Params and Query. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Remix params and query: access dynamic route params, parse search query strings, filter data, and manage URL state in loaders and components.

In this lesson, you'll work with URL parameters from dynamic segments and search query strings, using them to filter data and control page state.

What You'll Learn

How to access route params, parse and generate search query strings, filter data with search params, and keep UI state in the URL.

Why It Matters

URL params and queries make pages shareable and bookmarkable. State in the URL means users can share links to specific views, searches, or filtered states.

Real-World Use

DodaZIP's search page keeps filters and pagination in URL query params, letting users bookmark search results and share filtered views.

flowchart LR
    A[URL] --> B[Route Params: /:id]
    A --> C[Query: ?q=&page=]
    B --> D[Loader Filters]
    C --> E[Search & Pagination]
    style A fill:#121212,color:#fff

Route Params

Access dynamic segments:

export const loader = async ({ params }) => {
  const { categoryId, productId } = params;
  // Load product by category and ID
  return json(await getProduct(categoryId, productId));
};

In components:

import { useParams } from "@remix-run/react";

export default function Product() {
  const { categoryId, productId } = useParams();
  return <h1>Product {productId} in {categoryId}</h1>;
}

Search Query Params

Parse search params in loaders:

export const loader = async ({ request }) => {
  const url = new URL(request.url);
  const query = url.searchParams.get("q");
  const page = parseInt(url.searchParams.get("page") || "1");
  const sort = url.searchParams.get("sort") || "newest";
  
  const results = await searchProducts(query, { page, sort });
  
  return json({ results, query, page, sort });
};

Generating Search Params

Use useSearchParams() to read and update query strings:

import { useSearchParams } from "@remix-run/react";

export default function Search() {
  const [searchParams, setSearchParams] = useSearchParams();
  const query = searchParams.get("q") || "";
  
  const updateFilter = (key, value) => {
    setSearchParams(prev => {
      if (value) {
        prev.set(key, value);
      } else {
        prev.delete(key);
      }
      return prev;
    });
  };
  
  return (
    <div>
      <input
        value={query}
        onChange={(e) => updateFilter("q", e.target.value)}
      />
      <select onChange={(e) => updateFilter("sort", e.target.value)}>
        <option value="newest">Newest</option>
        <option value="price">Price</option>
      </select>
    </div>
  );
}

Filtering with Params

Combine params and query for complex filtering:

export const loader = async ({ params, request }) => {
  const url = new URL(request.url);
  const filters = {
    category: params.category,
    minPrice: url.searchParams.get("minPrice"),
    maxPrice: url.searchParams.get("maxPrice"),
    inStock: url.searchParams.has("inStock"),
    sort: url.searchParams.get("sort") || "newest",
    page: parseInt(url.searchParams.get("page") || "1"),
  };
  
  return json(await getFilteredProducts(filters));
};

Common Mistakes

  1. Not using new URL() for Parsing: request.url is a string. Wrap it in new URL() to access .searchParams.
  2. Forgetting integer parsing: url.searchParams.get("page") returns a string. Parse it with parseInt() for numeric values.
  3. Mutating search params directly: setSearchParams takes a callback that receives the current params. Don't mutate the previous value directly.
  4. Not handling missing params gracefully: URL params may be undefined. Provide defaults for missing values.
  5. Over-complicating URL state: Keep only essential state in the URL. Complex state should use Remix loaders or cookies.

Practice Questions

  1. How do you read a route param in a loader? Answer: Access params.paramName in the loader function arguments. The param name matches the $ segment in the filename.

  2. How do you parse search query strings in a loader? Answer: Create new URL(request.url) and use .searchParams.get("key") to read individual query parameters.

  3. What hook reads and updates search params in a component? Answer: useSearchParams() from @remix-run/react. It returns the current params and a setter function.

  4. Why keep state in the URL instead of React state? Answer: URL state is shareable, bookmarkable, and survives page refreshes. React state is lost on navigation.

Challenge

Build a product listing page with route params for category, search params for filters (price range, in-stock, sort), and pagination. All filter state should live in the URL.

Mini Project

Create a job board with search params for keyword, location, type (full-time/part-time), salary range, and page number. The URL should be shareable with all filters preserved.

FAQ

Can I use search params with forms?

: Yes. Use <Form method="get"> to submit form data as search params in the URL.

How do I handle array query params?

: Use url.searchParams.getAll("tag") for multiple values with the same key, like ?tag=a&tag=b.

What is the URL length limit for search params?

: Browsers support URLs up to 2048 characters. For very large datasets, use POST instead.

Can I use hash-based state in Remix?

: Yes. Access url.hash from the request URL. Update it with setSearchParams.

What's Next

Learn about Remix Sessions for managing user sessions and authentication state.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro