@protobuf-x/runtime
v0.1.1
Published
High-performance Protocol Buffers runtime for TypeScript & JavaScript. Zero dependencies, native bigint, faster and smaller than protobufjs.
Downloads
241
Maintainers
Readme
@protobuf-x/runtime
High-performance Protocol Buffers runtime for TypeScript & JavaScript. Zero dependencies.
The runtime library that powers code generated by @protobuf-x/codegen.
- 🚀 Faster than
protobufjson encode, decode, create, JSON, clone, and equals - 📦 Smallest runtime — minimal entry point is 3.4 KB brotli (vs 6.2 KB for protobufjs minimal)
- ✅ Zero dependencies — pure TypeScript, runs anywhere
- 🌐 Universal — Node.js, Deno, Bun, browsers, Cloudflare Workers, etc.
- 🔒 Type-safe — full TypeScript types with native
bigint(noLongwrapper)
Installation
npm install @protobuf-x/runtime
npm install -D @protobuf-x/codegenYou'll typically use this together with @protobuf-x/codegen which generates code that imports from this package.
Quick start
// schema_pb.ts is generated from schema.proto by @protobuf-x/codegen
import { User } from './gen/schema_pb.js'
// Construct
const alice = new User({ name: 'Alice', age: 30 })
// Encode
const bytes: Uint8Array = alice.toBinary()
// Decode
const decoded = User.decode(bytes)
console.log(decoded.name) // 'Alice'
// JSON
const json = User.toJSON(alice)
const back = User.fromJSON(json)Two entry points
Full (@protobuf-x/runtime) — 7.4 KB brotli
Includes everything: encode/decode, JSON, clone, equals, merge, streaming, services, extensions, well-known types, validation, freeze, patch, diff.
import {
Message,
BinaryReader,
BinaryWriter,
encodeDelimited,
decodeStream,
ServiceClient,
wellKnownToJSON
} from '@protobuf-x/runtime'Minimal (@protobuf-x/runtime/minimal) — 3.4 KB brotli
Encode/decode only. Use this for apps that just need binary serialization (RPC, message queues, storage, edge workers).
import { Message, BinaryReader, BinaryWriter } from '@protobuf-x/runtime/minimal'When you generate code with protobuf-x --runtime-package @protobuf-x/runtime/minimal,
the codegen automatically skips generating toJSON/fromJSON methods + JSON
interfaces (they're not needed at runtime), shrinking your bundle even further.
Performance
Benchmarks on bench.proto with 4 messages (Small/Address/Medium/Large), Node.js 25:
| Operation | protobuf-x | protobufjs | Ratio | | ------------- | --------------: | ---------: | ----: | | Encode small | 9.0M ops/s | 5.3M | 1.71x | | Encode medium | 1.7M ops/s | 1.2M | 1.43x | | Decode small | 10.6M ops/s | 8.8M | 1.21x | | Decode medium | 1.7M ops/s | 1.6M | 1.04x | | Create small | 27M ops/s | 12M | 2.16x | | toJSON small | 150M ops/s | 41M | 3.68x | | Clone medium | 833K ops/s | 500K | 1.65x |
See the main repo for full benchmark results.
Bundle size
| Library | Brotli (min) | | ------------------------------- | -----------: | | @protobuf-x/runtime/minimal | 3.4 KB | | protobufjs minimal | 6.2 KB | | @protobuf-x/runtime | 7.4 KB | | protobufjs full | 21.6 KB |
Architecture highlights
Two-pass encode
The two-pass approach (sizeOf + encodeTo) lets us allocate an exact-size
buffer up front and write sequentially with zero grow checks — much faster
than the growable-buffer approach used by protobufjs and @bufbuild/protobuf.
Inlined varint codec
Both encode and decode varints are fully inlined — no function calls per byte, no tuple allocations. The generated code uses these primitives directly.
Native Buffer fast paths on Node.js
When running on Node.js, strings use Buffer.utf8Slice / Buffer.utf8Write
which are 3-5x faster than TextEncoder / TextDecoder. The reader lazily
wraps Uint8Array inputs as Buffer on the first string read, so payloads
without strings pay nothing for the wrapping.
Native bigint
64-bit integers use the native bigint type — no Long polyfill, no
precision loss for large values, smaller bundle.
API surface (full runtime)
// Binary
import { BinaryReader, BinaryWriter, WireType } from '@protobuf-x/runtime'
// Encode helpers (used by generated code)
import {
varint32Size,
varint64Size,
int32Size,
strByteLen,
writeVarint,
writeVarint64,
writeInt32,
writeSint32,
writeFixed32,
writeFixed64,
writeBool,
writeBytes,
writeDouble,
writeFloat,
allocBuf,
finalizeBuf
} from '@protobuf-x/runtime'
// Message base
import { Message, type MessageType } from '@protobuf-x/runtime'
// Type system
import {
ScalarType,
FieldRule,
type FieldDescriptor,
type MessageDescriptor,
type EnumDescriptor
} from '@protobuf-x/runtime'
// Streaming
import { encodeDelimited, decodeStream, frame, Deframer } from '@protobuf-x/runtime'
// JSON
import { toJSON, fromJSON, wellKnownToJSON, wellKnownFromJSON } from '@protobuf-x/runtime'
// Utilities
import { equals, clone, merge, diff, patch, freeze, validate } from '@protobuf-x/runtime'
// Services
import { ServiceClient, type Transport } from '@protobuf-x/runtime'
// Pools
import { BufferPool, ObjectPool } from '@protobuf-x/runtime'Compatibility
- Wire format: 100% compatible with
protoc,protobufjs,@bufbuild/protobuf, Google's reference implementations, and any other compliant protobuf library. - Node.js: 18+
- Browsers: ES2022+ (Chrome 94+, Firefox 93+, Safari 16.4+)
- Runtimes: Deno, Bun, Cloudflare Workers, Vercel Edge, Netlify Edge
License
MIT
