querystringify

A small, dependency-free JavaScript library for parsing and building URL query strings, with built-in protection against prototype-pollution keys.

Library
npm
v2.2.0
175stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
36/100Needs Attention
Development Activity0
Maintenance0
Community64
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
55/100Fair
Architecture60
Code Quality65
Innovation50
Learning Curve45

querystringify is a lightweight JavaScript utility for converting between URL query strings and plain JavaScript objects. It exposes two functions — parse() to turn a query string into an object, and stringify() to turn an object back into a query string — with no runtime dependencies beyond the built-in encodeURIComponent/decodeURIComponent.

Originally created in 2014, before URLSearchParams was widely available in browsers, it favors simplicity over completeness: it only handles flat, single-level query strings and does not attempt to parse nested or array-style parameters. It also guards against prototype-pollution-style overrides during parsing, so keys like __proto__ or toString cannot silently override an object’s built-in properties.

What You Get

  • parse() function - Converts a query string (optionally prefixed with ? or #, or with no prefix at all) into a plain JavaScript object.
  • stringify() function - Converts a plain object back into a query string, with an optional ? prefix or a custom prefix string.
  • Prototype-safe parsing - Keys such as __proto__ or toString cannot override built-in object properties during parsing.
  • Zero runtime dependencies - A single ~2.5KB file with no external dependencies, safe to bundle for browser or Node.js.

Common Use Cases

  • Reading URL parameters in legacy browser targets - Projects that must support environments without native URLSearchParams use qs.parse(location.search) to read query parameters.
  • Building query strings for HTTP requests - Libraries construct request URLs by calling qs.stringify() on a params object before appending it to a base URL.
  • Router and history libraries - Client-side routing utilities use querystringify internally to serialize and deserialize route query state.
  • Serializing UI state to the address bar - Applications persist filter, sort, or pagination state into the URL by stringifying a state object and parsing it back on load.

Under The Hood

Architecture querystringify is architecturally minimal by design: a single index.js file exports two pure functions, parse() and stringify(), with no classes, no internal modules, and no shared state between them beyond two small private helpers (decode()/encode()) that wrap decodeURIComponent/encodeURIComponent in a try/catch. parse() uses a single regular expression to walk the query string and build a result object, explicitly guarding against key collisions and prototype-chain properties so a query string can’t clobber toString or __proto__. stringify() mirrors this by iterating own-property keys and joining encoded pairs. There is no configuration object beyond an optional prefix argument, and the core regex is effectively the only place complexity could grow.

Tech Stack The package ships as plain, dependency-free CommonJS (exports.stringify/exports.parse) targeting both Node.js and browser environments (via Browserify), with zero runtime dependencies. Its devDependencies are limited to mocha (test runner), c8 (coverage), assume (assertion library), and pre-commit (git hook runner). There is no build step, bundler, or transpiler — the single index.js file is published to npm as-is. CI runs on GitHub Actions across Node 14, 16, and 18, with coverage uploaded to Coveralls.

Code Quality Test coverage in test.js is thorough for such a small surface area: it exercises prefix handling (?, #, custom strings, none), edge cases like NaN/null/undefined/empty-string values, Symbol inputs, and explicit prototype-pollution attempts. Error handling favors silent try/catch fallbacks to null over throwing, which keeps the API forgiving for malformed input at the cost of swallowing errors internally. There is no TypeScript and no linter configuration in the repo, but CI enforces the test suite across three Node versions on every push and pull request, with coverage tracked through Coveralls.

API Design The public API is deliberately tiny — two symmetric verbs, parse() and stringify() — with no configuration required to get started and one optional prefix argument for flexibility. This mirrors the now-native URLSearchParams, which the README itself points readers toward first; querystringify’s remaining value is supporting older runtimes and giving callers a plain-object interface rather than an iterable API object. There’s no novel algorithm here — it’s a well-executed, minimal utility rather than an innovative one.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search