# URL Parameters vs Query Strings in Express.js – A Practical Guide

When building web applications with Express.js, you’ll frequently need to extract information from the URL. Express gives you two main tools for this: **URL parameters** (`req.params`) and **query strings** (`req.query`). Although they both live inside the URL, they serve different purposes. In this article, you’ll learn exactly what they are, how to use them, and when to choose one over the other.

## What Are URL Parameters?

URL parameters (often called **route parameters**) are **segments of the URL path** that act as placeholders. They are used to identify a specific resource – like a user profile, a product, or a blog post.

**Example:**  
`https://example.com/users/42`  
Here, `42` is a URL parameter representing a user ID.

In Express, you define parameters with a colon (`:`) in the route path:

```javascript
app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`User profile for ID: ${userId}`);
});
```

If the client visits `/users/42`, `req.params.id` will be `"42"`.

You can have multiple parameters:

```javascript
app.get('/posts/:year/:month/:slug', (req, res) => {
  const { year, month, slug } = req.params;
  // e.g., /posts/2026/04/hello-world
  res.json({ year, month, slug });
});
```

**Think of URL parameters as the “nouns” in your API – they identify *which* resource is being requested.**

## What Are Query Strings?

Query strings (or query parameters) are **key‑value pairs appended to the URL after a question mark (**`?`**)**. They are typically used to **filter, sort, paginate, or modify** the representation of a resource.

**Example:**  
`https://example.com/search?q=express&lang=en&page=2`

In Express, you access query strings via `req.query`:

```javascript
app.get('/search', (req, res) => {
  const { q, lang, page } = req.query;
  // For /search?q=express&lang=en&page=2
  res.send(`Searching for "${q}" in ${lang}, page ${page}`);
});
```

Query strings are **not part of the route definition** – Express parses them automatically for *any* route. They are always optional; a missing query key simply yields `undefined`.

## Key Differences at a Glance

| Aspect | URL Parameters (`req.params`) | Query Strings (`req.query`) |
| --- | --- | --- |
| **Place in URL** | Part of the path (e.g., `/users/:id`) | After `?` (e.g., `?sort=asc`) |
| **Purpose** | Identify a specific resource | Filter, sort, paginate, or modify output |
| **Required** | Usually required (route won’t match without them) | Always optional |
| **Express access** | `req.params` | `req.query` |
| **Syntactic character** | Use `:` in route definition | No route definition changes needed |
| **Example** | `/books/1984` | `/books?author=orwell&year=1949` |

## Accessing Params & Query Strings in Express – A Mini Cheatsheet

```javascript
const express = require('express');
const app = express();

// URL parameters: user profile
app.get('/users/:id', (req, res) => {
  console.log(req.params.id);   // "101"
  // ... fetch user from DB using id
});

// Query strings: search filters
app.get('/products', (req, res) => {
  console.log(req.query);       // { category: "shoes", color: "red" }
  // ... filter products based on query
});

// You can even combine both
app.get('/stores/:storeId/items', (req, res) => {
  const storeId = req.params.storeId;   // "7"
  const { category, maxPrice } = req.query;  // e.g., ?category=electronics&maxPrice=500
  res.json({ storeId, category, maxPrice });
});
```

## Real‑World Use Cases

### URL Parameters – User Profile Page

You want to show a user’s profile. The user ID is an **identifier** of *which* resource to retrieve.

```plaintext
GET /users/783
```

Route definition:

```javascript
app.get('/users/:userId', (req, res) => {
  const profile = getUserById(req.params.userId);
  res.render('profile', { profile });
});
```

### Query Strings – Search & Filters

On an e‑commerce product listing page, you want to refine the list by **filters** like category, brand, or price range.

```plaintext
GET /products?category=laptops&brand=apple&maxPrice=2000
```

Implementation:

```javascript
app.get('/products', (req, res) => {
  const { category, brand, maxPrice } = req.query;
  let products = getAllProducts();
  if (category) products = products.filter(p => p.category === category);
  if (brand)    products = products.filter(p => p.brand === brand);
  if (maxPrice) products = products.filter(p => p.price <= Number(maxPrice));
  res.json(products);
});
```

## When to Use Params vs. Query Strings – Rule of Thumb

*   **Use URL parameters** when the value is **essential to identify the resource** and without it the route wouldn’t make sense (e.g., `/articles/42`).
    
*   **Use query strings** for **optional modifiers** that refine the representation – sorting, filtering, pagination, language selection, etc.
    
*   If removing the parameter still leaves a meaningful endpoint, it’s probably a query string.
    
*   If the parameter is hierarchical (e.g., `/category/books/fiction`), keep it in the path.
    
*   For **RESTful APIs**, resources are located via the URL path; query strings provide additional instructions.
    

## Visual Breakdown of a URL

```plaintext
https://api.example.com/stores/8/products?category=shoes&color=red&page=3
\________________________/\______/\________/\__________________________/
        Origin              Params  (none   |          query string
                            (store  here)   |
                             ID = 8)        |
                           Resource path    |
```

*   `8` is a **URL parameter** (`req.params.storeId`).
    
*   `category=shoes`, `color=red`, `page=3` are **query parameters** (`req.query`).
    

* * *

## Quick Comparison Diagram (Text)

```plaintext
URL Parameters (PATH)
 ┌─────────────────────────────────┐
 │  /users/:id                     │   → Identifies exactly one resource
 │  /posts/:year/:month            │   → Often required, part of the path
 │  Access via: req.params         │
 └─────────────────────────────────┘

Query Strings (AFTER ?)
 ┌─────────────────────────────────┐
 │  /search?q=express&sort=desc   │   → Filters, sorts, or modifies output
 │  /products?page=2&limit=10     │   → Always optional
 │  Access via: req.query         │
 └─────────────────────────────────┘
```

* * *

## Summary

*   **URL parameters** (`req.params`) are for *identification*.
    
*   **Query strings** (`req.query`) are for *filtering/modification*.
    
*   Both can coexist – use the right tool for the right job to keep your API clean and predictable.
    

Now that you understand the difference, go ahead and refactor those messy routes! When your application logic separates “what resource” from “how to present it”, your code becomes easier to read, maintain, and scale.
