Express.js
Node.js
Web Development
JavaScript
Query String Variables

How to get GET (query string) variables in Express.js on Node.js?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Express.js, query string parameters from GET requests are available on req.query — a parsed object where each key maps to its value from the URL. For a request to /search?q=nodejs&page=2, req.query.q returns "nodejs" and req.query.page returns "2". Express parses the query string automatically using the qs library, so no additional middleware is needed.

Basic Usage

javascript
1const express = require('express');
2const app = express();
3
4app.get('/search', (req, res) => {
5    const query = req.query.q;
6    const page = req.query.page;
7    res.json({ query, page });
8});
9
10app.listen(3000);
11
12// GET /search?q=nodejs&page=2
13// Response: { "query": "nodejs", "page": "2" }

All req.query values are strings. If the URL has no query string, req.query is an empty object {}.

Accessing Multiple Parameters

javascript
1app.get('/api/products', (req, res) => {
2    const { category, minPrice, maxPrice, sort, order } = req.query;
3
4    console.log(category);  // "electronics"
5    console.log(minPrice);  // "100"
6    console.log(maxPrice);  // "500"
7    console.log(sort);      // "price"
8    console.log(order);     // "asc"
9
10    res.json({ category, minPrice, maxPrice, sort, order });
11});
12
13// GET /api/products?category=electronics&minPrice=100&maxPrice=500&sort=price&order=asc

Use destructuring for clean access to multiple parameters.

Type Conversion

Query string values are always strings. Convert them explicitly:

javascript
1app.get('/api/items', (req, res) => {
2    // String to number
3    const page = parseInt(req.query.page, 10) || 1;
4    const limit = parseInt(req.query.limit, 10) || 20;
5
6    // String to boolean
7    const active = req.query.active === 'true';
8
9    // String to float
10    const lat = parseFloat(req.query.lat) || 0;
11    const lng = parseFloat(req.query.lng) || 0;
12
13    res.json({ page, limit, active, lat, lng });
14});
15
16// GET /api/items?page=3&limit=50&active=true&lat=40.7128&lng=-74.0060

Default Values

javascript
1app.get('/api/users', (req, res) => {
2    const page = parseInt(req.query.page, 10) || 1;
3    const limit = Math.min(parseInt(req.query.limit, 10) || 20, 100);
4    const sort = req.query.sort || 'createdAt';
5    const order = req.query.order || 'desc';
6    const search = req.query.q || '';
7
8    // Use defaults when parameters are missing
9    res.json({ page, limit, sort, order, search });
10});
11
12// GET /api/users           → { page: 1, limit: 20, sort: "createdAt", ... }
13// GET /api/users?page=3    → { page: 3, limit: 20, sort: "createdAt", ... }

Arrays in Query Strings

Express supports arrays via repeated keys or bracket notation:

javascript
1app.get('/api/filter', (req, res) => {
2    const tags = req.query.tags;
3    console.log(tags);
4    res.json({ tags });
5});
6
7// GET /api/filter?tags=node&tags=express&tags=mongodb
8// tags = ["node", "express", "mongodb"]
9
10// GET /api/filter?tags[]=node&tags[]=express
11// tags = ["node", "express"]
12
13// GET /api/filter?tags=node
14// tags = "node" (string, not array — only one value!)

When only one value is provided, req.query.tags is a string, not an array. Normalize it:

javascript
const tags = [].concat(req.query.tags || []);
// Always an array, even with 0 or 1 values

Nested Objects

Express uses the qs library by default, which supports nested objects:

javascript
1app.get('/api/search', (req, res) => {
2    const filters = req.query.filter;
3    console.log(filters);
4    res.json({ filters });
5});
6
7// GET /api/search?filter[status]=active&filter[role]=admin
8// filters = { status: "active", role: "admin" }

req.query vs req.params vs req.body

javascript
1// req.params — URL path parameters (from route definition)
2app.get('/users/:id', (req, res) => {
3    req.params.id;  // "42" from /users/42
4});
5
6// req.query — query string parameters (after ?)
7app.get('/users', (req, res) => {
8    req.query.page;  // "2" from /users?page=2
9});
10
11// req.body — POST/PUT request body (needs middleware)
12app.post('/users', express.json(), (req, res) => {
13    req.body.name;  // From JSON body: { "name": "Alice" }
14});

Validation with express-validator

javascript
1const { query, validationResult } = require('express-validator');
2
3app.get('/api/search',
4    query('q').isString().trim().notEmpty().withMessage('Search query required'),
5    query('page').optional().isInt({ min: 1 }).toInt(),
6    query('limit').optional().isInt({ min: 1, max: 100 }).toInt(),
7    (req, res) => {
8        const errors = validationResult(req);
9        if (!errors.isEmpty()) {
10            return res.status(400).json({ errors: errors.array() });
11        }
12        const { q, page = 1, limit = 20 } = req.query;
13        res.json({ q, page, limit });
14    }
15);

URL Encoding

Special characters in query strings must be URL-encoded:

javascript
1// Client side
2const searchTerm = 'hello world & more';
3const url = `/search?q=${encodeURIComponent(searchTerm)}`;
4// /search?q=hello%20world%20%26%20more
5
6// Express decodes automatically
7app.get('/search', (req, res) => {
8    console.log(req.query.q);  // "hello world & more"
9});

Common Pitfalls

  • Values are always strings: req.query.page is "2", not 2. Use parseInt() or parseFloat() for numbers, and === 'true' for booleans. Forgetting this causes bugs in comparisons and arithmetic.
  • Missing parameters are undefined: req.query.missing returns undefined, not null or empty string. Use || default or optional chaining req.query.key?.trim().
  • Single value vs array inconsistency: ?tag=one gives a string, ?tag=one&tag=two gives an array. Always normalize with [].concat(req.query.tag || []).
  • Query string size limits: Express defaults to a max query string length of 1000 characters. Override with app.set('query parser', qs => qs.parse(qs, { parameterLimit: 5000 })) if needed.
  • Prototype pollution: The qs parser protects against __proto__ injection by default in modern Express versions, but always validate and sanitize query parameters before using them in database queries.

Summary

  • Use req.query to access GET query string parameters — no middleware needed
  • All values are strings; convert explicitly with parseInt(), parseFloat(), or boolean comparison
  • Provide default values with || default for optional parameters
  • Arrays are supported via repeated keys (?a=1&a=2) or bracket notation (?a[]=1&a[]=2)
  • Use req.params for URL path segments, req.query for query strings, req.body for POST data
  • Validate query parameters with express-validator for production APIs

Course illustration
Course illustration

All Rights Reserved.