DEV Community

Cover image for qs-fast: a drop-in faster qs (2.3 parse, 3.8 stringify, identical output)
Jeet Dhandha
Jeet Dhandha

Posted on • Originally published at npmjs.com

qs-fast: a drop-in faster qs (2.3 parse, 3.8 stringify, identical output)

qs is the query-string parser behind Express's extended query parsing and a huge amount of HTTP-handling code. It's careful, spec-faithful, and security-hardened — it has to be, because it parses untrusted input. That carefulness also means it does a lot of work on every call, even for the boring, common case of a=1&b=2&c=3.

qs-fast is a drop-in replacement that fast-paths that common case — 2.3× faster parse, 3.8× faster stringify — with byte-for-byte identical output, and no loss of qs's safety behavior.

Fast-path the easy case, fall back for everything else

The core idea: qs-fast handles the default-options path with a hand-rolled parser and stringifier, and transparently bails to real qs the moment anything non-trivial shows up:

  • non-default options (custom delimiter, allowDots, custom charset, …)
  • deep nesting (depth > 5)
  • __proto__ / prototype-pollution vectors
  • array index overflow
  • cyclic object input
  • anything else outside the fast lane

So you never trade away qs's correctness or its security hardening — you just skip its overhead when it's provably safe to. qs is a runtime dependency, and encoding goes through qs's own qs/lib/utils so the bytes match exactly.

// before
import qs from "qs";

// after
import qs from "@libs-jd/qs-fast";
Enter fullscreen mode Exit fullscreen mode
npm i @libs-jd/qs-fast
Enter fullscreen mode Exit fullscreen mode

The benchmark

Measured on Node v24 / V8, best-of-7, against qs@6 — every case checked for identical output first:

op qs qs-fast speedup
stringify (typical objects) 0.0277 ms 0.0072 ms 3.8×
parse (typical query strings) 0.0634 ms 0.0275 ms 2.3×

In the correctness gate, the fast path covered 96% of parse and 100% of stringify workloads; the rest fell through to real qs and still returned identical results.

The part that matters: identical output

Same rule as any honest optimization — prove it before you trust it. qs-fast ships a 142-case gate (nested objects, arrays, encoded characters, edge cases, and the fallback triggers themselves) asserting the output is identical to real qs. 0 mismatches, run in CI on every change. When in doubt, it defers to qs, so the failure mode is "as fast as qs," never "wrong."

Links

MIT licensed. If you parse a lot of query strings, swap the import and see.

Top comments (1)

Collapse
 
frank_signorini profile image
Frank

"I'm impressed by the performance gains qs-fast achieves, especially considering the identical output. Have you explored how qs-fast handles edge cases like nested query parameters, and if there are any plans to integrate it into Express's default query parsing?"