Open-source project
zandaqo/structurae avatar
zandaqo/structurae

Structurae and the JavaScript data structures the language never shipped

Data structures for high-performance JavaScript applications.

732 stars22 forksTypeScriptMIT

At a glance

What is it?
Structurae is a TypeScript library of data structures for JavaScript, spanning a binary protocol built on DataView, bit and grid structures, sorted collections, and graph implementations. Its sharpest feature is the schema-driven binary layer, and its sharpest constraint is that the schema has to be written by hand.
Who is it for?
Structurae fits engineers who need binary encoding with per field access, packed bit storage, or graph algorithms in a browser or Node.js service, and who are willing to describe their payload as a JSON Schema. It does not fit teams that want a graph library with no schema step, that need dynamic object shapes, or that would rather stay with the built in Map, Set and Array.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A collection of structures JavaScript leaves to you

Structurae describes itself as "a collection of data structures for high-performance JavaScript applications", and the repository layout backs that up. The root directory holds one file per structure: `bit-array.ts`, `bit-field.ts`, `big-bit-field.ts`, `ranked-bit-array.ts`, `pool.ts`, `binary-heap.ts`, `sorted-array.ts`, `grid.ts`, `binary-grid.ts`, `symmetric-grid.ts`, `graph.ts`, and four separate adjacency matrix variants for weighted and unweighted, directed and undirected cases.

The point of the collection is that the language ships none of these. JavaScript gives you Array, Map, Set and typed arrays, and a graph traversal or a priority queue is something each project writes again. The library is aimed at people who need those structures with predictable memory layout or with algorithms that plain arrays make awkward.

The topics listed for the repository give the same picture: array, bigint, binary, bitfield, graphs, matrices, sorted and typescript. There are no runtime dependencies in `package.json`, so nothing else is pulled into your bundle to get a heap.

View extends DataView so buffers can hold strings and objects

The most distinctive part of Structurae is not the classic structures but the binary protocol. JavaScript represents binary data with ArrayBuffer and reads it through TypedArrays and DataView, and both of those are limited to numbers. Structurae adds classes that extend the DataView interface so a buffer can hold strings, objects and arrays as well, and those extended classes are what the README calls views.

The `View` class is the entry point. It handles creating and caching the structures needed for a given JSON Schema and simplifies serialization of tagged objects. A view created from a schema is itself a DataView subclass, so it stays compatible with code that already expects one.

The payoff is that a field can be read or written without decoding the whole object. The README calls this zero copy operation, and it is the reason to care about this library if your payloads are large and your fields are selectively accessed.

The schema is JSON Schema, so no compilation step sits between you and the bytes

Layout is declared with JSON Schema rather than a code generator or an IDL compiler. A schema with an `$id`, a `type` of `object`, and a `properties` map produces a typed view class:

typescript
const AnimalView = view.create<Animal>({
  $id: "Pet",
  type: "object",
  properties: {
    name: { type: "string", maxLength: 10 },
    // by default, type `number` is treated as int32, but can be further specified usin `btype`
    age: { type: "number", btype: "uint8" },
  },
});

The generic parameter is the TypeScript interface for the payload, so the view class is statically typed. The README lists four properties of the protocol: it is smaller and faster than schema-less binary formats such as BSON and MessagePack, it supports zero copy operations, it supports static typing through TypeScript, and it does not require compilation, unlike most schema-based formats such as FlatBuffers.

That last point is the trade-off. With FlatBuffers you get a generated accessor layer and pay for a build step. Here the schema is data that the runtime reads, so there is no generated code to keep in sync, and no compiler in the toolchain.

Objects default to a fixed layout, and maps are the exception you opt into

By default, objects are treated as C-like structs. Data is laid out sequentially with fixed sizes, and all standard JavaScript values are supported, including nested objects and fixed size arrays. A string field needs its size declared through `maxLength`, and an array needs `maxItems` with all items of the same type.

Objects that carry optional fields or variable size fields take a different form. The README instructs you to add `btype` `map` and list the non-optional fields in `required`:

typescript
const TownView = view.create<Town>({
    $id: "Town",
    type: "object",
    btype: "map",
    properties: {
      // notice that maxLength is not required for optional fields in maps
      // however, if set, map with truncate longer strings to fit the maxLength
      name: { type: "string" },
      railstation: { type: "boolean" },
      // optional, nullable field
      clacks: { type: "integer" },
    }
    required: ["railstation"],
  });

Two things follow from that. A map instance has a size that is calculated rather than fixed, so each record costs more than a struct record, and an optional field that is absent simply reads back as `undefined`. The README also notes that if `maxLength` is set on a map field, longer strings are truncated to fit, which is a silent data loss path worth checking in your own use.

Bit storage and object pools target allocation pressure

The bit structures are a separate family. `BitField` and `BigBitField` store and operate on data inside Numbers and BigInts, treating those values as bitfields. `BitArray` is an array of bits implemented on top of `Uint32Array`, and `RankedBitArray` extends it with O(1) rank and O(log N) select methods, which is the data structure you reach for when you need to count bits below a given position quickly.

`Pool` sits alongside them and manages the availability of objects in object pools. In a JavaScript runtime where allocation pressure drives garbage collection, reusing objects through a pool is a direct lever, and Structurae treats it as a first class structure rather than an afterthought.

None of these are exotic algorithms. They are well known designs implemented in TypeScript with the package focused on making them usable without pulling in separate dependencies. The repository also carries a `benchmarks/` directory, though the README does not publish any numbers from it, so the performance claims in the description are not verifiable from the documentation.

Graph and grid classes come in list, matrix and symmetric variants

The graph family is split into two layers. The adjacency structures implement adjacency list and adjacency matrix data structures, and there are four matrix files covering the weighted or unweighted and directed or undirected combinations. On top of that, `Graph` extends an adjacency list or matrix structure and adds traversal with BFS and DFS, pathfinding with Dijkstra and Bellman-Ford, and spanning tree construction with BFS and Prim.

The grids are similarly layered. `BinaryGrid` builds a grid or two dimensional matrix of bits. `Grid` extends built-in indexed collections to handle two dimensional data such as nested arrays. `SymmetricGrid` stores symmetric or triangular matrices using half the space a normal grid needs, which is the option to reach for when your matrix is symmetric and you have been paying for the mirrored half.

The cost of this range is interface surface. Each variant is a separate class with its own methods, so a codebase that picks the wrong one early will find itself rewriting call sites later. `Pool`, `SortedArray` and `BinaryHeap` extend `Array` rather than wrapping it, which keeps them familiar to anyone who already works with JavaScript collections.

Installing with npm, importing in Node.js or Deno

The library is published to npm, and the README gives a single install command for Node.js:

shell
npm i structurae

The package is an ES module. `package.json` sets `"type": "module"`, the main entry is `./esm/index.js`, and the exports map publishes both the root and a wildcard path so individual modules can be imported directly. The import itself is a named import:

javascript
import {...} from "structurae";

Deno users are pointed at a hosted module rather than npm:

typescript
import {...} from "https://deno.land/x/structurae/index.ts"

A first real use is creating a view and encoding an object into it:

typescript
// encode our animal object
const animal = AnimalView.from({ name: "Gaspode", age: 10 });
animal instanceof DataView; //=> true
animal.byteLength; //=> 14
animal.get("age"); //=> 10
animal.set("age", 20);
animal.toJSON(); //=> { name: "Gaspode", age: 20 }

What you should see is an object that is a DataView, a byte length matching the fixed layout of the schema, and a `get` that returns the decoded value. Note that the version in `package.json` is 4.0.2, so the major number has moved several times and the API of the version you install may differ from older examples in blog posts linked from the README.

Maintenance, licensing and the limits of the documentation

The repository is not archived, and the last push was on 2026-10-11. It has no GitHub releases, so version history lives in `CHANGELOG.md` rather than in tagged release notes, and the current published version is 4.0.2.

The licence is MIT, which is the least restrictive of the common open source licences and covers commercial use and modification without a copyleft obligation. The full text sits in the `LICENSE` file at the root.

On documentation, the README is a fair summary but it stops mid sentence on how map instance size is calculated, and the details of the bit structures, the graph algorithms and the pool are left to the linked articles and to the type declarations in the source. The repository also includes `tests/`, `benchmarks/`, `examples/` and a `_build.ts` file that appears to drive the build, plus a `deno.jsonc` for the Deno side. If your adoption depends on the exact behaviour of rank and select in `RankedBitArray`, or on whether the graph classes accept weighted edges on the list variant, the source and the test suite are where you will find the answer, not the README.

Editorial conclusion

Structurae fits engineers who need binary encoding with per field access, packed bit storage, or graph algorithms in a browser or Node.js service, and who are willing to describe their payload as a JSON Schema. It does not fit teams that want a graph library with no schema step, that need dynamic object shapes, or that would rather stay with the built in Map, Set and Array. Verify first that your payload can be described with the fixed size struct layout or the map layout the View class supports, because objects with variable size fields need the `btype: "map"` form and the README does not describe mixed layouts inside one buffer.

Frequently asked questions

How do I install Structurae in a Node.js project?

The README gives a single npm command, `npm i structurae`. The package is an ES module, so it is imported with a named import such as `import {...} from "structurae";`, and the wildcard export in `package.json` also allows importing individual modules directly.

Can I use Structurae with Deno?

Yes. The README shows the Deno import pointing at the hosted module, `import {...} from "https://deno.land/x/structurae/index.ts"`, and the repository root contains `deno.jsonc` and `deno.lock` files for the Deno side of the project.

What is the difference between a struct layout and a map layout in Structurae?

Objects are treated as C-like structs by default, laid out sequentially with fixed sizes, where strings need a `maxLength` and arrays need `maxItems`. Objects with optional or variable size fields must instead set `btype` to `map` and list the fixed sized fields in `required`, which makes the instance size calculated rather than fixed.

Which graph algorithms does Structurae provide?

The `Graph` class extends an adjacency list or matrix structure and provides BFS and DFS traversal, Dijkstra and Bellman-Ford pathfinding, and spanning tree construction with BFS and Prim. The adjacency structures are implemented separately for list and matrix, with weighted and unweighted, directed and undirected matrix variants.

Does Structurae need a build or compile step for its binary protocol?

No. The README states that the protocol does not require compilation unlike most other schema-based formats, and that it uses JSON Schema for schema definitions with static typing through TypeScript.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. zandaqo/structurae on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zandaqo-structurae.svg)](https://hysenlabs.com/projects/zandaqo-structurae)

Was this useful?