JavaScript
Node benchmarks run on V8 with performance.now() converted to nanoseconds.
Runtime
What it is
This suite measures Node.js, not JavaScript running in a web browser. Node.js is a command-line host that embeds the V8 JavaScript engine, which is the same engine Chrome uses. V8 JIT-compiles (just-in-time compiles) hot functions into native code and reclaims unused objects with a garbage collector. Node also provides Buffer, require/import, and native addons written in C++.
| This suite | |
|---|---|
| Host | Node.js 18 or newer and npm |
| Engine | V8 inside Node.js, not a browser |
| Prepare | Install Node with your package manager, then run npm install in javascript/ |
| Run | javascript/scripts/run-benchmarks.sh |
| Memory | V8 garbage collector |
What this suite runs
package.json requires Node 18 or newer. Timing uses performance.now() and converts the result to nanoseconds. There is no stream mode. Every codec is timed on in-memory buffers only.
What changes the numbers
V8 compiles hot functions after they have run a few times, so early repetitions can be slower than later ones. Libraries that reuse an Encoder or Packr instance, such as cbor-x and msgpackr, avoid setup work on every call. v8-serialize is a Node-only format. It is not JSON and it is not portable to other languages. Optional native addons such as simdjson are left out of a run when they are not installed.
Calling JSON.stringify in a browser on the same payload is a different environment from this Node runner.
Suite-specific gotchas
devalue is a framework value codec used by tools such as SvelteKit. It is not a portable wire format.
The row named simdjson-parse+JSON.stringify uses SIMD only for parse. Serialize is still the standard JSON.stringify.
These times cannot be ranked against another language, or against a browser.
Where to go next
The steps to install Node and run the benchmark are in javascript/README.md. The platform overview is Introduction to Node.js.
Benchmark runner
javascript/(repository root)- Logs:
logs/javascript/YYYY-MM-DD-HHMMSS.csv - Registration: modular under
javascript/src/serializers/ prepare()compiles schemas / reuses encoder instances outside timed loops- Protobuf codegen:
npm run generate:protobuf(protobuf-es + google-protobuf; needs suite protoc sysroot for jspb stubs)
Serializers
| Name | Category | Package | Optimal API |
|---|---|---|---|
| @msgpack/msgpack | Binary | @msgpack/msgpack |
encode / decode |
| avsc | Schema | avsc |
Type.forSchema + toBuffer / fromBuffer |
| bebop | Schema | bebop |
BebopView JSON-model primitives |
| bser | Binary | bser |
dumpToBuffer / loadFromBuffer |
| bson | Binary | bson |
BSON.serialize / deserialize |
| cbor | Binary | cbor |
encode / decodeFirstSync |
| cbor-x | Binary | cbor-x |
reused Encoder / Decoder |
| devalue | Native | devalue |
stringify / parse |
| fast-json-stringify | JSON | fast-json-stringify |
compile once + JSON.parse |
| flatbuffers | Schema | flatbuffers |
Builder / ByteBuffer |
| flexbuffers | Schema | flatbuffers (FlexBuffers) |
encode / toObject |
| google-protobuf | Schema | google-protobuf |
official jspb serializeBinary / deserializeBinary |
| json-pack-msgpack | Binary | @jsonjoy.com/json-pack |
MsgPackEncoder / MsgPackDecoder |
| JSON.stringify | JSON | builtin | JSON.stringify / JSON.parse |
| msgpackr | Binary | msgpackr |
reused Packr / Unpackr |
| protobuf-es | Schema | @bufbuild/protobuf |
create + toBinary / fromBinary |
| protobufjs | Schema | protobufjs |
real fixture Type.encode / decode |
| sia | Binary | @timeleap/sia |
typed-tag JSON-model over Sia primitives |
| simdjson-parse+JSON.stringify | JSON | simdjson (optional) |
ser: JSON.stringify; deser: simdjson.parse |
| v8-serializer | Native | node:v8 |
v8.serialize / v8.deserialize |
Specifics
Why each library exists, what problem it was written to solve, and how. Names link to the source repository (or the stdlib / in-tree path this suite times). A version after the name is the last measured SerializerVersion from this suite's latest bench.
@msgpack/msgpack · 3.1.3
The official MessagePack JavaScript implementation (@msgpack/msgpack). MessagePack was created as compact binary JSON. This package is the reference encode/decode API for JS.
avsc · 5.7.9
avsc brings Apache Avro to JavaScript. Avro was created for compact, schema-driven records in data pipelines. avsc solves the JS side with Type.forSchema and buffer encode/decode.
bebop · 3.2.3
Bebop is a schema-driven binary format created as a simpler, faster alternative to protobuf-like IDL stacks for games and services. The problem was heavy generated code and slow encoders. Bebop solves it with a compact schema and generated writers.
bser · 2.1.1
BSER is Facebook Watchman's binary protocol: a compact encoding for the watchman's client/server messages. The problem was JSON overhead in a local file-watching daemon. This row times the Node bser dump/load path.
bson · 6.10.4
BSON (Binary JSON) was created for MongoDB so documents could be stored and traversed without a text parse. Official language drivers implement that spec. This row times that library's serialize/deserialize path.
cbor · 9.0.2
node-cbor implements IETF CBOR (RFC 8949) for Node. CBOR exists as the IETF's binary JSON-like format. The library is a full encode/decode implementation of that RFC.
cbor-x · 1.6.6
cbor-x is a high-performance CBOR encoder/decoder for JS, from the same author as msgpackr. The problem was slow or allocating CBOR stacks in Node. It solves that with reusable Encoder/Decoder instances.
devalue · 5.9.2
devalue was written (SvelteKit and friends) to stringify richer JavaScript values than JSON allows — dates, maps, cyclical graphs — without eval. The problem was JSON's limited types and eval-based hydrators. devalue solves it with a custom text format.
fast-json-stringify · 6.4.0
fast-json-stringify was created in the Fastify ecosystem to serialize JSON from a JSON Schema much faster than JSON.stringify. The problem was that schema-known objects still paid for a fully dynamic walk. It compiles a serializer once and reuses it; this suite decodes with JSON.parse.
flatbuffers · 24.12.23
FlatBuffers was created at Google so games and clients could access serialized data without an unpack step. The problem was that protobuf-style decode allocated a full object graph. FlatBuffers solves it with a schema and a binary layout that can be traversed in place.
flexbuffers · 24.12.23
FlexBuffers is the schemaless cousin of FlatBuffers. It was created so you can have a FlatBuffers-family binary without compiling a schema. The same Google repository implements it.
google-protobuf · 3.21.4
This is Google's official JavaScript protobuf runtime (google-protobuf / jspb). It exists so the same .proto contracts can run in JS. The suite times serializeBinary / deserializeBinary.
json-pack-msgpack · 18.30.0
json-pack (jsonjoy) is a family of binary codecs including MessagePack. It was written to give JavaScript a fast, modular binary JSON toolkit. This row times the MsgPack encoder/decoder.
JSON.stringify · node-24.15.0
JSON.stringify / JSON.parse are the ECMAScript standard JSON APIs. They exist so every JavaScript host can speak RFC 8259 without a library. This row times Node's V8 implementation.
msgpackr · 1.12.1
msgpackr was written for high-throughput MessagePack in Node, with reusable Packr/Unpackr instances. The problem was that generic MessagePack libraries allocated too much per call. msgpackr solves that with a performance-oriented encoder/decoder.
protobuf-es · 2.15.0
protobuf-es is Buf's Protocol Buffers implementation for ECMAScript. The problem was that existing JS protobuf stacks did not match modern TypeScript and the official proto3 feature set. It generates TypeScript and times toBinary / fromBinary.
protobufjs · 7.6.6
protobuf.js is a popular JavaScript Protocol Buffers implementation that can work from a .proto or a JSON descriptor. The problem was that Google's JS protobuf was awkward in Node. protobuf.js solves it with a JS-native API.
sia · 2.3.0
Sia is Timeleap's compact binary tag format for JS values. It was created as a project-specific, typed binary encoding rather than a public interchange standard. This row times those primitive writers.
simdjson-parse+JSON.stringify · 0.9.2
simdjson was created to parse JSON at memory-bandwidth speeds using SIMD. The problem was that conventional parsers were far from hardware limits. This row uses simdjson only for parse; serialize is still JSON.stringify. Only deserialize uses SIMD; serialize is stdlib JSON.stringify.
v8-serializer · v8-13.6.233.17-node.48
Node's v8.serialize / v8.deserialize snapshot V8 values. They exist so the engine can persist structured clones, not as a portable wire format. This row times that Node-only API.
Stream I/O
Not measured. The Node suite times the same buffer serialize / deserialize path for every codec; there is no distinct stream API loop. The benchmark runner emits bytes only so the Dashboard / this runner does not claim a second I/O mode. See Modes — stream honesty.
Notes
- simdjson-parse+JSON.stringify (optional native addon; omitted from the run if not installed): only deserialize uses SIMD; serialize is stdlib
JSON.stringify(honest leaderboard label). - protobuf-es / google-protobuf use generated code from
javascript/schemas/js_fixtures.proto(field shapes match JS data types; string timestamps). Google stubs live undersrc/generated/google/(npm run generate:google-protobuf). - flatbuffers / flexbuffers: fixture support via tables / FlexBuffers; see the benchmark runner for float/array workarounds.
- bebop / sia encode a JSON-shaped model via each library’s primitive writers.
- devalue is a framework-oriented value codec (SvelteKit), not a portable wire standard.
- prepare() builds native messages and compiles schemas outside the timed path.
Also: javascript/README.md.
Numbers
Measured numbers for this language live on the Dashboard (pre-filtered). Claim level is L1 (one machine, one session) — see Claims and replication.