DEV Community

Alex Spinov
Alex Spinov

Posted on

Protobuf-ES Has Free Type-Safe Protocol Buffers for TypeScript — Here's Why It's Better Than protobufjs

Protocol Buffers in JavaScript used to be painful. Protobuf-ES from the Buf team makes it feel native to TypeScript.

What is Protobuf-ES?

Protobuf-ES is a complete Protocol Buffers implementation for TypeScript and JavaScript. It generates idiomatic TypeScript code with full type safety — no any types, no manual casting.

Quick Start

bun add @bufbuild/protobuf
bun add -d @bufbuild/protoc-gen-es @bufbuild/buf
Enter fullscreen mode Exit fullscreen mode

Define your schema:

// proto/user.proto
syntax = "proto3";

package user.v1;

message User {
  string id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
  repeated string roles = 5;
  Address address = 6;
}

message Address {
  string street = 1;
  string city = 2;
  string country = 3;
}

message GetUserRequest {
  string id = 1;
}

message GetUserResponse {
  User user = 1;
}
Enter fullscreen mode Exit fullscreen mode

Generate TypeScript:

npx buf generate
Enter fullscreen mode Exit fullscreen mode

Using Generated Code

import { create, toBinary, fromBinary, toJson } from "@bufbuild/protobuf";
import { UserSchema, AddressSchema } from "./gen/user_pb";

// Create a message
const user = create(UserSchema, {
  id: "user_123",
  name: "Alice Johnson",
  email: "alice@example.com",
  age: 30,
  roles: ["admin", "developer"],
  address: create(AddressSchema, {
    street: "123 Main St",
    city: "San Francisco",
    country: "US",
  }),
});

// Serialize to binary (3-10x smaller than JSON)
const bytes = toBinary(UserSchema, user);
console.log(bytes.length); // ~50 bytes vs ~200+ for JSON

// Deserialize
const decoded = fromBinary(UserSchema, bytes);
console.log(decoded.name); // "Alice Johnson"

// Convert to JSON
const json = toJson(UserSchema, user);
Enter fullscreen mode Exit fullscreen mode

Why Protobuf-ES Over protobufjs

Feature Protobuf-ES protobufjs
TypeScript First-class Bolted on
Bundle Size Tree-shakeable Large
Generated Code Idiomatic TS Verbose
Type Safety Full Partial
ECMAScript Modern Legacy
Maintained Active (Buf team) Sporadic

With Connect-ES (gRPC for the Web)

import { ConnectRouter } from "@connectrpc/connect";
import { UserServiceSchema } from "./gen/user_connect";

export default (router: ConnectRouter) =>
  router.service(UserServiceSchema, {
    async getUser(req) {
      const user = await db.findUser(req.id);
      return { user };
    },
  });
Enter fullscreen mode Exit fullscreen mode

Need efficient data serialization for scraping pipelines? Check out my Apify actors — structured data at scale. For custom solutions, email spinov001@gmail.com.

Top comments (0)