Create protoc code-generation plugins easily in nodejs

Downloads in past


0.0.67 years ago7 years agoMinified + gzip package size for protoc-plugin in KB


Create protoc code-generation plugins easily in nodejs


npm i -S protoc-plugin


You can checkout the code in the example/ dir, but here is a quick example:
#! /usr/bin/env node
const protocPlugin = require('protoc-plugin')

protocPlugin(protos => {
  // do stuff here with protos
  // return array like [{name: 'filename', content: 'CONTENTS'}]

Make sure not to output anything to stdout (for example with console.log) because protoc uses stdout. I use console.error to output stuff to the user.
Since it's a promise, you can throw or just return Promise.reject('reason'), and you can do async stuff with promises.
Once you have made your plugin, save it as protoc-gen-NAME, give it executable permissions, then run it like this:
protoc --plugin=protoc-gen-NAME --NAME_out=generated yourfile.proto

If you put it in your path, you don't need the --plugin=protoc-gen-NAME part.
PRO TIP - use npm's bin in your package.json to get your plugin script installed, cross-platform, in the user's path.


There is a utility included for finding comments in various places in the protobuf file. It's a lil obtuse, but you can look in the spec for more info.
Here are some locationList addresses I use a lot in protoc plugins:
* [4, m] - message comments
* [4, m, 2, f] - field comments in message
* [6, s] - service comments
* [6, s, 2, r] - rpc comments in service

  • m - the method count in the proto, from index 0
  • f - the field-count in the method, from index 0
  • s - the service definition in the proto, from index 0
  • r - the RPC definition in the service, from index 0

like this:
// [4, 0] is right here 
message MyMessage {
  // [4, 0, 2, 0] is right here
  int32 field1 = 1;

// [6, 0] is right here
service MyService {
  // [6, 0, 2, 0] is here!
  rpc (MyMessage) returns (MyMessage);

There are more addresses, but you will have to look at the the spec to figure it out.


const protocPlugin = require('protoc-plugin')
const findCommentByPath = protocPlugin.findCommentByPath

// output comments for services & messages to stderr
protocPlugin(protos => {
  protos.forEach(proto => {
    proto.serviceList.forEach((service, s) => {
      console.error('SERVICE',, findCommentByPath([6, s], proto.sourceCodeInfo.locationList))
      service.methodList.forEach((rpc, r) => {
        console.error('RPC',, findCommentByPath([6, s, 2, r], proto.sourceCodeInfo.locationList))
    proto.messageList.forEach((message, m) => {
      console.error('MESSAGE',, findCommentByPath([4, m], proto.sourceCodeInfo.locationList))
      message.fieldList.forEach((field, f) => {
        console.error('FIELD',, findCommentByPath([4, m, 2, f], proto.sourceCodeInfo.locationList))
  // no files written
  return []

advanced usage

If you need more from the incoming stdin CodeGeneratorRequest have a look at example/protoc-gen-extendedlogger.


I am currently including google/api/annotations proto file, so gRPC-annotions will work out of the box (for example see proto/helloworld.proto) For any other extensions, you will need to generate the google-protobuf representation, and require it before parsing. You can easily generate them with a command like this:
protoc --js_out=import_style=commonjs,binary:YOURDIR/ -I PROTODIR/ PROTODIR/YOURFILE.proto

then require like this:

You can see how I have done this with google/api/annotations_pb in index.js.