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
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;
}
Generate TypeScript:
npx buf generate
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);
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 };
},
});
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)