js-sdsl review
js-sdsl 4.4.2 brings C++ STL-shaped containers to JavaScript: a heap-backed PriorityQueue, indexed Deque, red-black-tree OrderedMap and OrderedSet, plus Vector, LinkList, Stack, Queue, HashMap, and HashSet. Calls such as `pushBack`, `lowerBound`, `eraseElementByIterator`, and `getElementByPos` make algorithm ports easier, but they do not behave like native `Array`, `Map`, `Set`, or standard iterators. Version 4.4.2 is still the current npm release from July 2023; repository work continued in 2026 without a newer package release.
js-sdsl 4.4.2 installed in 0.6 seconds as one dependency-free package, and its full browser bundle measured 48 KB minified; it earns its place when a heap, deque, or ordered tree solves a measured problem. Ordinary application state should stay on native collections, especially when object keys are frozen or primitive identity must match `Map`.
We installed it
| Install | ✓ · 0.6s | 1 package on disk · 2 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 7.8 KB | gzipped (48 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does js-sdsl install cleanly?
Yes. In a fresh container with an empty cache, npm install js-sdsl finished in 0.6s, leaving 1 package and 2 MB on disk. npm audit reported no known vulnerabilities.
How much does js-sdsl add to a browser bundle?
7.8 KB gzipped (48 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does js-sdsl work with both ESM and CommonJS?
Yes. Both import 'js-sdsl' and require('js-sdsl') worked in Node 22 in our run. The package is published as CommonJS.
Does js-sdsl include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
js-sdsl or mnemonist: which should you use?
mnemonist: Use it for JavaScript-oriented heaps, deques, tries, indexes, and other specialized structures rather than an STL-shaped surface. js-sdsl 4.4.2 installed in 0.6 seconds as one dependency-free package, and its full browser bundle measured 48 KB minified; it earns its place when a heap, deque, or ordered tree solves a measured problem.
When should you not use js-sdsl?
A native Array, Map, or Set meets the complexity requirement. Their APIs are familiar, engine-optimized, and add no package or bundle cost.
Use it if
- A measured workload needs a heap, double-ended queue, or sorted map or set that JavaScript does not provide natively.
- You are translating an STL-based algorithm and names such as `lowerBound`, `begin`, `end`, and `pushBack` reduce translation errors.
- You want ten typed containers with no runtime or peer dependencies and need both CommonJS and ESM loading.
- Browser code can pay a 48 KB minified bundle for the full import, or can install one of the separately published container packages.
- A native `Array`, `Map`, or `Set` meets the complexity requirement. Their APIs are familiar, engine-optimized, and add no package or bundle cost.
- You need JavaScript iterator semantics. js-sdsl iterators are mutable container objects; `next()` advances the same object, and reading `pointer` at `end()` throws.
- Map keys require exact native identity rules. The 4.4.2 hash implementation can coerce primitive keys through an object property table, so numeric `1` and string `1` are unsafe as distinct keys.
- Object keys may be frozen or non-extensible. HashMap and HashSet tag object keys with `Object.defineProperty`, which mutates the object and can throw.
- You expect the current source branch to match npm. Version 4.4.2 was released in July 2023 while GitHub was pushed in April 2026.
- You need a trustworthy hosted manual. The README's official site has redirected to unrelated content, so this guide uses the repository URL and shipped declarations instead.
Setup reality
We installed js-sdsl 4.4.2 in 0.6 seconds in a fresh Node 22 Bookworm sandbox. It left 1 package and 2 MB on disk. npm audit found 0 known vulnerabilities. The package declares 0 direct and 0 peer dependencies, is 1,480 KB unpacked, and bundles TypeScript declarations. Both require() and ESM import worked even though this CommonJS package has no exports map.
The full browser probe measured 48 KB minified and 7.8 KB gzipped. Named imports may tree-shake with your bundler, but resolution depends on the package's main and module fields rather than an exports map. The project also publishes isolated packages such as @js-sdsl/deque; use one when a browser only needs a single structure. No credentials, native build, environment variables, or config files are involved.
The learning cost is semantic. size() is a method, length is a getter, vectors use getElementByPos, and maps use setElement. A find or bound call returns a mutable iterator that you compare with end(). Tree containers need a stable total-order comparator for object keys. If a compared property changes while the key is stored, remove and reinsert it or the tree order no longer matches the data.
PriorityQueue comparator direction deserves a test: (a, b) => a - b puts the smaller number on top. Vector and PriorityQueue can skip their normal shallow input copy when the constructor's copy flag is false, so later mutation may be shared. For identity-sensitive keys, use native Map and Set. Version 4.4.2's hash containers attach symbols to object keys and do not reproduce native primitive-key behavior.
Patterns
Process highest-priority work first use-max-priority-queue
import { PriorityQueue } from 'js-sdsl'
type Job = { id: string; priority: number }
const jobs = new PriorityQueue<Job>([], (a, b) => b.priority - a.priority)
jobs.push({ id: 'email', priority: 2 })
jobs.push({ id: 'incident', priority: 10 })
console.log(jobs.pop()?.id) // incidentFor object jobs, test the comparator with two known values. The item returned by `top()` defines what this package considers highest priority.
Create a min-heap for shortest distance use-min-priority-queue
import { PriorityQueue } from 'js-sdsl'
const distances = new PriorityQueue<number>([], (a, b) => a - b)
distances.push(30)
distances.push(5)
distances.push(12)
console.log(distances.top()) // 5
console.log(distances.pop()) // 5In js-sdsl, `(a, b) => a - b` makes a numeric min-heap. `pop()` returns `undefined` when the queue is empty.
Push and pop at both ends use-double-ended-queue
import { Deque } from 'js-sdsl'
const deque = new Deque<number>()
deque.pushBack(2)
deque.pushFront(1)
deque.pushBack(3)
console.log(deque.front(), deque.back()) // 1 3
deque.popFront()
deque.popBack()Deque avoids repeated `Array.shift()` or `unshift()` work on large queues. An empty `popFront()` or `popBack()` returns `undefined`.
Keep map entries sorted by key use-ordered-map
import { OrderedMap } from 'js-sdsl'
const scores = new OrderedMap<string, number>([], (a, b) => a.localeCompare(b))
scores.setElement('zoe', 8)
scores.setElement('ada', 10)
console.log(scores.getElementByKey('ada')) // 10
console.log([...scores]) // [['ada', 10], ['zoe', 8]]The comparator decides both order and key equivalence. It must return zero only for keys that should occupy one map entry.
Find the first sorted key at or above a target find-lower-bound
import { OrderedSet } from 'js-sdsl'
const values = new OrderedSet([10, 20, 40, 50])
const iterator = values.lowerBound(25)
if (!iterator.equals(values.end())) {
console.log(iterator.pointer) // 40
}Check against `end()` before reading `pointer`; the end iterator has no element and throws when dereferenced.
Build a sorted unique sequence deduplicate-in-order
import { OrderedSet } from 'js-sdsl'
const unique = new OrderedSet([5, 1, 5, 3, 1])
console.log(Array.from(unique)) // [1, 3, 5]
unique.insert(2)
unique.eraseElementByKey(5)OrderedSet keeps comparator order and supports bounds. Native Set is simpler when insertion order is enough.
Use indexed STL-style sequence operations use-vector
import { Vector } from 'js-sdsl'
const vector = new Vector([10, 20, 30])
vector.pushBack(40)
vector.setElementByPos(1, 25)
vector.insert(2, 99)
console.log(vector.getElementByPos(2)) // 99
console.log([...vector]) // [10, 25, 99, 30, 40]Out-of-range vector positions throw `RangeError`. Use an Array unless the STL-style method set helps the surrounding algorithm.
Merge two sorted linked lists use-linked-list
import { LinkList } from 'js-sdsl'
const odd = new LinkList([1, 3, 5])
const even = new LinkList([2, 4, 6])
odd.merge(even)
console.log([...odd]) // [1, 2, 3, 4, 5, 6]Both linked lists must already be sorted compatibly before `merge`. Indexed access still walks the list.
Choose LIFO or FIFO behavior explicitly use-stack-and-queue
import { Queue, Stack } from 'js-sdsl'
const pending = new Queue(['first', 'second'])
console.log(pending.front()) // first
console.log(pending.pop()) // first
const history = new Stack(['first', 'second'])
console.log(history.top()) // second
console.log(history.pop()) // secondQueue exposes the front and Stack exposes the top. For a small collection, an Array plus an index or push/pop is usually clearer.
Erase through a mutable container iterator erase-while-iterating
import { OrderedSet } from 'js-sdsl'
const set = new OrderedSet([1, 2, 3, 4, 5])
for (let iterator = set.begin(); !iterator.equals(set.end());) {
if (iterator.pointer % 2 === 0) {
iterator = set.eraseElementByIterator(iterator)
} else {
iterator.next()
}
}
console.log([...set]) // [1, 3, 5]`eraseElementByIterator` returns the next position. Calling `next()` mutates the existing iterator instead of returning an `IteratorResult`.
Keep object identity keys in native Map avoid-hash-object-keys
const metadata = new Map<object, string>()
const frozenKey = Object.freeze({ id: 1 })
metadata.set(frozenKey, 'ready')
console.log(metadata.get(frozenKey)) // readyjs-sdsl 4.4.2 tags object keys and can throw on a frozen object. Native Map preserves object identity without mutating the key.
Install only the deque package for browser code install-isolated-container
npm install @js-sdsl/deque
import Deque from '@js-sdsl/deque'
const events = new Deque<string>()
events.pushBack('connected')The repository publishes each container separately. Verify that the isolated package version and import shape match the main package before mixing them.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| mnemonist | npm | Use it for JavaScript-oriented heaps, deques, tries, indexes, and other specialized structures rather than an STL-shaped surface. |
| denque | npm | Use it when a double-ended queue is the only missing structure and a small focused API is preferable. |
| heap-js | npm | Use it for heap and priority-queue work without importing a ten-container collection. |
| immutable | npm | Use it when persistent immutable collections and structural sharing are the actual requirements. |
More data guides
numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

