ts-proto: TypeScript Protobuf Generator
ts-proto is a TypeScript code generation tool that transforms Protocol Buffer (`.proto`) schemas into strongly-typed, idiomatic TypeScript files. It provides robust type definitions for messages and services, along with utilities for encoding, decoding, and JSON serialization. Currently at version 2.11.6, the project maintains an active release cadence, with frequent bug fixes and feature enhancements, as seen in the recent 2.11.x releases addressing issues like `globalThis.Buffer` casting, `isolatedDeclarations` compatibility, and `NullValue` handling. A significant differentiator for ts-proto v2.x is its migration from the `protobufjs` library to `@bufbuild/protobuf` for low-level serialization, aiming for improved performance and maintainability. It also supports generating client implementations for various RPC frameworks including Twirp, gRPC-web, gRPC-js, and NestJS, offering a comprehensive solution for integrating Protobuf with TypeScript applications.
Common errors
-
TypeError: Writer is not a constructor
cause Attempting to use `protobufjs` Writer/Reader classes with `ts-proto` v2.x or later, which now uses `@bufbuild/protobuf` internally.fixUpdate your code to import `BinaryReader` and `BinaryWriter` from `@bufbuild/protobuf/wire` instead of `protobufjs`. -
protoc-gen-ts_proto: program not found or is not executable
cause The `protoc` compiler cannot find or execute the `ts-proto` plugin. This is often due to an incorrect path or permissions, especially on Windows.fixVerify the path to `protoc-gen-ts_proto` in your `node_modules/.bin` directory. On Windows, use the `.cmd` extension and the specific quoting/path format: `protoc --plugin=protoc-gen-ts_proto=".\node_modules\.bin\protoc-gen-ts_proto.cmd" --ts_proto_out=. ./simple.proto`. Ensure the file is executable. -
TS2307: Cannot find module './my_proto_file' or its corresponding type declarations.
cause TypeScript cannot resolve the generated `.ts` files, often because the `protoc` command hasn't been run, or the output directory is not included in `tsconfig.json`'s `include` or `paths`.fixFirst, run the `protoc` command to generate the TypeScript files. Then, ensure your `tsconfig.json` includes the output directory (e.g., `"include": ["src", "./"]`) and that `"moduleResolution": "node"` or `"node16"` is set.
Warnings
- breaking ts-proto v2.x migrated its underlying Protobuf serialization library from `protobufjs` to `@bufbuild/protobuf`. Code directly using `protobufjs`'s `Writer` or `Reader` classes will break and needs to be updated.
- gotcha When running `protoc` on Windows, the plugin path requires a slightly different syntax due to how paths and arguments are handled.
- gotcha Generated code is ESM-first. If your project uses CommonJS, you might need to configure your build tools or Node.js environment appropriately. Older `protobufjs` patterns of `require()` might not work directly.
- gotcha Ensure you are using a modern `protoc` compiler. Older versions (e.g., `protoc 3.0.0`) may not support the `--ts_proto_opt` flag or other features required by `ts-proto`.
Install
-
npm install ts-proto -
yarn add ts-proto -
pnpm add ts-proto
Imports
- Person
const { Person } = require('./person');import { Person } from './person'; - PingService
import PingService from './service';
import { PingService } from './service'; - BinaryReader, BinaryWriter
import { Writer, Reader } from 'protobufjs/minimal';import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
Quickstart
/* simple.proto */
syntax = "proto3";
package example;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
}
message PingRequest {
string message = 1;
}
message PingResponse {
string message = 1;
}
service PingService {
rpc Ping(PingRequest) returns (PingResponse);
}
// Terminal commands
// 1. Install ts-proto
npm install ts-proto
// 2. Install protoc (if not already installed, see grpc.io/docs/protoc-installation)
// 3. Generate TypeScript files
protoc \
--plugin=./node_modules/.bin/protoc-gen-ts_proto \
--ts_proto_out=. \
./simple.proto
// Generated usage example (e.g., in index.ts)
// import { Person, PingService } from './simple';
//
// const person: Person = { name: 'Alice', id: 123, email: 'alice@example.com' };
// console.log('Person:', Person.toJSON(person));
//
// const pingRequest: PingRequest = { message: 'Hello, gRPC!' };
// // In a real app, you would have a client implementation for PingService
// // For example, a mock client:
// class MockPingServiceClient implements PingService {
// ping(request: PingRequest): Promise<PingResponse> {
// console.log('Mock Ping request:', request.message);
// return Promise.resolve({ message: `Pong: ${request.message}` });
// }
// }
//
// const client = new MockPingServiceClient();
// client.ping(pingRequest).then(response => {
// console.log('Mock Ping response:', response.message);
// });