# Customizing protobuf code generation with plugin API: A Complete Guide

> Learn to customize protobuf code generation using the plugin API. Discover how protoc interacts with plugins for tailored code generation. A complete guide.

- Repository: [Protocol Buffers/protobuf](https://github.com/protocolbuffers/protobuf)
- Tags: how-to-guide
- Published: 2026-03-02

---

**The Protocol Buffers compiler (`protoc`) supports custom code generation through a plugin API where the compiler sends a `CodeGeneratorRequest` to a plugin binary via STDIN, and the plugin returns a `CodeGeneratorResponse` containing generated files via STDOUT.**

The `protocolbuffers/protobuf` repository provides a powerful extension mechanism for the `protoc` compiler. By implementing the plugin API, developers can customize protobuf code generation to produce language bindings, documentation, validation logic, or build artifacts while maintaining full compatibility with the standard compilation workflow.

## How the Protobuf Plugin API Works

The plugin architecture follows a strict request-response cycle orchestrated by `protoc`:

1. **`protoc` builds a `CodeGeneratorRequest`** containing all `FileDescriptor` objects for the current compilation.
2. The request is serialized and written to **STDIN** of the plugin binary (invoked via `--plugin` or discovered via `PATH`).
3. The plugin's **`PluginMain`** entry point reads the request, delegates to a concrete implementation of the abstract `CodeGenerator` interface, and writes a `CodeGeneratorResponse` to **STDOUT**.
4. `protoc` reads the response and materializes the generated files on disk.

This design decouples the compiler from language-specific logic, allowing any custom generator to participate in the build pipeline without modifying `protoc` itself.

## Core Components and Source Files

The plugin API surface is defined in several key headers within the repository:

| Component | Role | Key Symbols | Source Path |
|-----------|------|-------------|-------------|
| **Plugin entry point** | Boilerplate wiring `protoc` to generator | `PluginMain(int argc, char* argv[], const CodeGenerator* generator)` | [`src/google/protobuf/compiler/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.h) |
| **Code generator interface** | Abstract contract for custom generators | `class CodeGenerator { virtual bool Generate(...) = 0; ... }` | [`src/google/protobuf/compiler/code_generator.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/code_generator.h) |
| **Request/Response protos** | Serialized data exchanged on stdio | `CodeGeneratorRequest`, `CodeGeneratorResponse` | [`src/google/protobuf/compiler/plugin.pb.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.pb.h) |
| **Parameter parsing** | Parses `--myplugin_out=key=val` options | `ParseGeneratorParameter` | [`src/google/protobuf/compiler/code_generator_lite.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/code_generator_lite.h) |
| **UPB plugin API** | Lightweight C API alternative | `upb::generator::PluginMain`, `upb::generator::CodeGenerator` | [`upb_generator/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/upb_generator/plugin.h) |

## Implementing a Custom Plugin

### Minimal C++ Plugin Example

The following example demonstrates a complete plugin that generates a text file for each input `.proto`:

```cpp
// hello_plugin.cc
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/printer.h>
#include <iostream>

using namespace google::protobuf;
using namespace google::protobuf::compiler;

class HelloGenerator : public CodeGenerator {
 public:
  bool Generate(const FileDescriptor* file,
                const std::string& /*parameter*/,
                GeneratorContext* ctx,
                std::string* error) const override {
    // Build output filename: <proto_name>.hello.txt
    std::string out_name = file->name() + ".hello.txt";

    // Open stream via GeneratorContext abstraction
    io::ZeroCopyOutputStream* raw_out = ctx->Open(out_name);
    io::Printer printer(raw_out, '$');

    printer.Print("// Generated by HelloGenerator for $filename$\n",
                  "filename", file->name());
    printer.Print("// Package: $package$\n", "package", file->package());

    return true;
  }
};

int main(int argc, char* argv[]) {
  HelloGenerator gen;
  return PluginMain(argc, argv, &gen);
}

```

### Building and Running the Plugin

Compile the plugin binary and invoke it via `protoc`:

```bash

# Compile against libprotobuf and libprotoc

g++ -std=c++17 hello_plugin.cc -lprotobuf -lprotoc -o protoc-gen-hello

# Ensure binary is in PATH or use --plugin flag

protoc --hello_out=. my_message.proto

# Generates: my_message.proto.hello.txt

```

The `PluginMain` function in [`src/google/protobuf/compiler/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.h) handles all request parsing and response serialization, so the custom implementation only needs to override the `Generate` method.

### Parsing Generator Parameters

Plugins receive command-line parameters via the `--myplugin_out=key=value` syntax. Parse these using the utility in [`code_generator_lite.h`](https://github.com/protocolbuffers/protobuf/blob/main/code_generator_lite.h):

```cpp
bool Generate(const FileDescriptor* file,
              const std::string& parameter,
              GeneratorContext* ctx,
              std::string* error) const override {
  // Parameter format: key1=val1,key2=val2
  std::vector<std::pair<std::string, std::string>> opts;
  google::protobuf::compiler::ParseGeneratorParameter(parameter, &opts);
  
  for (const auto& p : opts) {
    if (p.first == "prefix") prefix_ = p.second;
  }
  // Generate using parsed prefix_...
}

```

## UPB-Based Plugin API

For projects requiring a lightweight, header-only runtime, the UPB (micro protobuf) library provides an alternative plugin interface. The architecture mirrors the C++ API but uses UPB's `Arena` and `DefPool` for descriptor management.

Key differences:
- Entry point: `upb::generator::PluginMain` in [`upb_generator/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/upb_generator/plugin.h)
- Generator base class: `upb::generator::CodeGenerator`
- Context: `upb::generator::GeneratorContext`

Example UPB plugin structure:

```cpp
// upb_hello_plugin.cc
#include "upb_generator/plugin.h"
#include "upb_generator/file_layout.h"
#include "google/protobuf/compiler/code_generator_lite.h"

class UpbHelloGenerator : public upb::generator::CodeGenerator {
 public:
  bool Generate(const google::protobuf::FileDescriptor* file,
                const std::string& parameter,
                upb::generator::GeneratorContext* ctx,
                std::string* error) const override {
    std::string out = file->name() + ".upb.h";
    auto out_stream = ctx->Open(out);
    out_stream->Write("// UPB hello for package ", file->package(), "\n");
    return true;
  }
};

int main(int argc, char* argv[]) {
  UpbHelloGenerator gen;
  return upb::generator::PluginMain(argc, argv, &gen);
}

```

## Summary

- **The protobuf plugin API** enables custom code generation by implementing the `CodeGenerator` interface and using `PluginMain` as the entry point.
- **Core files** defining the contract are located in [`src/google/protobuf/compiler/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.h), [`code_generator.h`](https://github.com/protocolbuffers/protobuf/blob/main/code_generator.h), and [`plugin.pb.h`](https://github.com/protocolbuffers/protobuf/blob/main/plugin.pb.h).
- **Communication flow** involves `protoc` sending a `CodeGeneratorRequest` to the plugin's STDIN and receiving a `CodeGeneratorResponse` via STDOUT.
- **Parameter parsing** is handled by `ParseGeneratorParameter` from [`code_generator_lite.h`](https://github.com/protocolbuffers/protobuf/blob/main/code_generator_lite.h), allowing key=value pairs from `--plugin_out` flags.
- **UPB alternative** provides a lightweight C API via [`upb_generator/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/upb_generator/plugin.h) for embedded or mobile scenarios.

## Frequently Asked Questions

### What is the protobuf plugin API?

The protobuf plugin API is the extension mechanism built into the `protoc` compiler that allows external binaries to generate custom code. It defines a standard interface where `protoc` serializes compilation metadata into a `CodeGeneratorRequest` message, sends it to a plugin process, and receives generated file contents back through a `CodeGeneratorResponse` message.

### How do I pass parameters to a protobuf plugin?

Parameters are passed via the `--plugin_out` command-line flag using the syntax `--myplugin_out=key=value,flag:output_dir`. Inside the plugin, the `Generate` method receives these parameters as a single string, which should be parsed using `google::protobuf::compiler::ParseGeneratorParameter` from [`src/google/protobuf/compiler/code_generator_lite.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/code_generator_lite.h) to extract individual key-value pairs.

### What is the difference between C++ and UPB plugins?

C++ plugins use the full `libprotoc` runtime and implement the `CodeGenerator` interface defined in [`src/google/protobuf/compiler/code_generator.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/code_generator.h), providing rich descriptor introspection. UPB plugins use a lightweight, header-only runtime suitable for embedded systems, implementing `upb::generator::CodeGenerator` from [`upb_generator/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/upb_generator/plugin.h) with lower memory overhead but similar architectural patterns.

### Where is PluginMain defined?

`PluginMain` is declared in [`src/google/protobuf/compiler/plugin.h`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.h) and serves as the standard entry point for C++ plugins. It handles the boilerplate of reading the `CodeGeneratorRequest` from STDIN, dispatching to the concrete `CodeGenerator` implementation, and writing the `CodeGeneratorResponse` to STDOUT, allowing developers to focus solely on file generation logic.