{
  "title": "querry-cleaner: Express Middleware to Fix Duplicate Query Parameters",
  "slug": "querry-cleaner",
  "topic": "hots",
  "url": "https://harshcodez.com/hots/querry-cleaner",
  "formats": {
    "html": "https://harshcodez.com/hots/querry-cleaner",
    "markdown": "https://harshcodez.com/hots/querry-cleaner.md",
    "json": "https://harshcodez.com/hots/querry-cleaner.json"
  },
  "excerpt": "Duplicate query params cause silent bugs. querry-cleaner is a lightweight Express middleware that deduplicates them in one line — zero config, zero dependencies.",
  "content": "# Querry-Cleaner — Fixing Duplicate Query Parameters in Express\n\nDuplicate query parameters are a real problem. A request like `/search?page=1&sort=name&page=2` can cause inconsistent behavior — some frameworks return the first value, some return the last, and some return an array where your code expects a string.\n\nThis is known as **HTTP Parameter Pollution**, and it's both a bug source and a security concern.\n\n**querry-cleaner** is a zero-dependency Express middleware that deduplicates query parameters before they reach your route handlers.\n\n## Install\n\n```bash\nnpm install querry-cleaner\n```\n\n## Usage\n\n```typescript\nimport express from \"express\";\nimport queryCleaner from \"querry-cleaner\";\n\nconst app = express();\napp.use(queryCleaner());\n\napp.get(\"/search\", (req, res) => {\n  // req.url is already clean — no duplicate keys\n  res.json({ query: req.query });\n});\n\napp.listen(3000);\n```\n\nThat's it. One line to add, zero config needed.\n\n### Before & After\n\n| Incoming request | What your handler sees |\n|---|---|\n| `/search?page=1&sort=name&page=2` | `/search?page=2&sort=name` |\n| `/api?token=abc&token=xyz` | `/api?token=xyz` |\n\nThe last value wins — consistent, predictable behavior.\n\n## Whitelist\n\nNeed certain routes to stay untouched? Pass a whitelist:\n\n```typescript\napp.use(\n  queryCleaner({\n    whitelist: [\"/webhooks/stripe\", \"/health\"],\n  })\n);\n```\n\nWhitelisted paths skip cleaning entirely.\n\n## How It Works\n\nThe core logic is ~15 lines. It uses the built-in `URL` and `URLSearchParams` APIs — no external dependencies.\n\n```typescript\nconst parsedUrl = new URL(req.url, \"http://localhost\");\nconst cleanParams = new URLSearchParams();\n\nparsedUrl.searchParams.forEach((value, key) => {\n  cleanParams.set(key, value); // .set() overwrites, .append() would keep both\n});\n\nreq.url = parsedUrl.pathname + \"?\" + cleanParams.toString();\n```\n\nThe trick is `.set()` vs `.append()` — calling `.set()` on an existing key overwrites it, so only the last value survives. The middleware rebuilds `req.url` with the cleaned params before calling `next()`.\n\n## Links\n\n- **npm**: [querry-cleaner](https://www.npmjs.com/package/querry-cleaner)\n- **GitHub**: [harshcodezzz/querry-cleaner](https://github.com/harshcodezzz/querry-cleaner)\n- **License**: [MIT](https://raw.githubusercontent.com/harshcodezzz/querry-cleaner/refs/heads/main/LICENSE)\n\n\n\n",
  "author": {
    "name": "Harshcodez",
    "avatar": "https://yt3.googleusercontent.com/dVQ45fRC_U-zqx70LPY7RigWrtkyNIwQXykX997cfWHCm1f2m-EBYeLgQnFYmp9JGRQl5mt_TA=s120-c-k-c0x00ffffff-no-rj",
    "bio": "Developer and Blogger"
  },
  "tags": [
    "express",
    "nodejs",
    "npm",
    "middleware",
    "open-source",
    "typescript"
  ],
  "coverImage": "https://api.harshcodez.com//api/posts/19/file/API%20Query%20Cleaner.png",
  "readingTime": 2,
  "publishedAt": "2026-07-24",
  "updatedAt": "2026-07-24",
  "seo": {
    "title": "querry-cleaner: Express Middleware to Fix Duplicate Query Parameters",
    "description": "A zero-dependency Express middleware that removes duplicate URL query parameters, preventing HTTP Parameter Pollution bugs and keeping your API responses predictable.",
    "keywords": [
      "express",
      "nodejs",
      "npm",
      "middleware",
      "open-source",
      "typescript"
    ]
  }
}