# How to Use the protoc-gen-go-lite Plugin for Efficient Go Code Generation

> Learn to use protoc-gen-go-lite for static, reflection-free Go code generation. Boost performance with faster serialization, marshaling, and more, replacing standard Go protobuf plugins.

- Repository: [Aperture Robotics/protobuf-go-lite](https://github.com/aperturerobotics/protobuf-go-lite)
- Tags: how-to-guide
- Published: 2026-02-25

---

**The `protoc-gen-go-lite` plugin generates static, reflection-free Go code for protobuf serialization, serving as a high-performance replacement for both `protoc-gen-go` and `protoc-gen-go-vtprotobuf` with optimized methods for marshaling, unmarshaling, size calculation, and equality checks.**

The `aperturerobotics/protobuf-go-lite` repository provides a specialized protocol buffer compiler plugin designed for resource-constrained environments like TinyGo or performance-critical services where reflection overhead is unacceptable. Unlike the standard Go protobuf implementation, `protoc-gen-go-lite` produces **static method implementations** that eliminate runtime reflection while maintaining full wire-format compatibility with standard protobuf messages.

## What Is protoc-gen-go-lite?

`protoc-gen-go-lite` is a `protoc` plugin that combines the functionality of the standard Go protobuf generator with the performance optimizations of vtprotobuf. It generates Go source files containing **static implementations** for:

- **Serialization**: `MarshalVT()`, `MarshalToVT()`, `MarshalToSizedBufferVT()`
- **Deserialization**: `UnmarshalVT()`
- **Size calculation**: `SizeVT()`
- **Cloning and equality**: `CloneVT()`, `EqualVT()`
- **JSON handling**: JSON marshaling and unmarshaling methods

The plugin is built with a modular architecture where each feature is implemented as a separate generator in the `features/` directory, allowing you to include only the functionality your application requires.

## Installation

Install the `protoc-gen-go-lite` binary using `go install`:

```bash
go install github.com/aperturerobotics/protobuf-go-lite/cmd/protoc-gen-go-lite@latest

```

Ensure your `$GOBIN` (or `$GOPATH/bin`) is in your system `PATH` so that `protoc` can locate the plugin binary.

## Command-Line Flags and Configuration

The plugin entry point in [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go) parses two primary flags that control code generation behavior:

### --allow-empty

When specified, this flag permits the generation of empty [`.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/.pb.go) files. By default, the generator skips files that would contain no code.

### --features

This comma-separated or plus-separated list specifies which code generation features to enable. The default value is `"all"`, which enables every available feature.

Available feature options include:

- `size` – Generates `SizeVT()` methods for calculating serialized message size
- `marshal` – Generates `MarshalVT()`, `MarshalToVT()`, and `MarshalToSizedBufferVT()` methods
- `unmarshal` – Generates `UnmarshalVT()` methods for parsing wire-format data
- `equal` – Generates `EqualVT()` methods for deep equality comparison
- `clone` – Generates `CloneVT()` methods for creating deep copies
- `json` – Generates JSON marshaling and unmarshaling helpers
- `marshal_strict` – Generates strict marshaling variants
- `unmarshal_unsafe` – Generates unsafe unmarshaling variants for performance

In [`generator/generator.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/generator.go), the `NewGenerator` function resolves these feature names to concrete implementations located in the `features/` directory (e.g., `features/marshal`, `features/unmarshal`).

## Generating Go Code

### Basic protoc Invocation

To generate Go code using the plugin, invoke `protoc` with the `--plugin` and `--go-lite_out` options:

```bash
protoc \
  --plugin=protoc-gen-go-lite="${GOBIN}/protoc-gen-go-lite" \
  --go-lite_out=. \
  example.proto

```

This command generates [`example.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/example.pb.go) containing the message definitions and all default features (when using `features=all`).

### Selecting Features with the --features Flag

For optimized builds where you only need specific functionality, pass the `features` option:

```bash
protoc \
  --plugin=protoc-gen-go-lite="${GOBIN}/protoc-gen-go-lite" \
  --go-lite_out=. \
  --go-lite_opt=features=marshal+unmarshal+size+equal+clone \
  example.proto

```

This generates only the `MarshalVT`, `UnmarshalVT`, `SizeVT`, `EqualVT`, and `CloneVT` methods, reducing binary size by excluding JSON or strict marshaling code.

## Understanding the Generated Code

The generated Go files combine output from two distinct generation phases:

1. **Base definitions**: The `generator_base.GenerateFile` function emits standard Go structs, enums, and getter methods that mirror the upstream `protobuf-go` output, ensuring API compatibility.

2. **Feature methods**: Each enabled feature generator (located in `features/<feature_name>/`) adds static methods to the generated types. For example, the `features/marshal` generator adds:

```go
func (m *Person) MarshalVT() ([]byte, error)
func (m *Person) MarshalToVT(dAtA []byte) (int, error)
func (m *Person) MarshalToSizedBufferVT(dAtA []byte) (int, error)

```

These implementations avoid reflection by using pre-computed wire types and direct memory operations, making them suitable for TinyGo and high-performance microservices.

## Using the Generated Code in Your Application

After generating your [`.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/.pb.go) files, use the static methods directly without importing `google.golang.org/protobuf/proto` for basic operations:

```go
package main

import (
    "log"
    "example" // import path generated from the proto package
)

func main() {
    // Create a message instance
    p := &example.Person{
        Name: "Alice",
        Age:  30,
    }

    // Marshal to wire format without reflection
    data, err := p.MarshalVT()
    if err != nil {
        log.Fatal(err)
    }

    // Unmarshal into a new instance
    var q example.Person
    if err := q.UnmarshalVT(data); err != nil {
        log.Fatal(err)
    }

    // Verify equality using static comparison
    if !p.EqualVT(&q) {
        log.Fatalf("messages differ: got %+v, want %+v", q, p)
    }

    log.Printf("Successfully serialized and deserialized: %+v", q)
}

```

The `MarshalVT` and `UnmarshalVT` methods allocate minimal memory and avoid the reflection overhead present in the standard `proto.Marshal` and `proto.Unmarshal` functions.

## Summary

- **`protoc-gen-go-lite`** generates static, reflection-free Go code from protobuf definitions, replacing both `protoc-gen-go` and `protoc-gen-go-vtprotobuf`.
- The plugin supports **selective feature generation** via the `--features` flag, allowing you to include only `marshal`, `unmarshal`, `size`, `equal`, `clone`, `json`, or other specific functionality.
- Entry point logic resides in [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go), while the core generation logic is implemented in [`generator/generator.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/generator.go) with modular feature generators located in `features/`.
- Generated code provides **zero-allocation serialization** suitable for TinyGo and high-performance microservices through methods like `MarshalVT()`, `UnmarshalVT()`, and `SizeVT()`.

## Frequently Asked Questions

### How does protoc-gen-go-lite differ from the standard protoc-gen-go?

The standard `protoc-gen-go` generates Go code that relies on the `google.golang.org/protobuf` runtime and uses reflection for marshaling and unmarshaling operations. In contrast, `protoc-gen-go-lite` produces **static method implementations** that perform serialization and deserialization without reflection, resulting in smaller binary sizes and better performance in constrained environments like TinyGo or high-throughput services.

### Can I use protoc-gen-go-lite with existing protobuf files that were generated by other tools?

Yes, `protoc-gen-go-lite` generates Go structs that are wire-compatible with standard protobuf messages. However, the generated code uses method names like `MarshalVT` and `UnmarshalVT` instead of the standard `Marshal` and `Unmarshal` methods. To migrate existing code, you will need to update your application to call these static methods directly, or use the generated types alongside standard protobuf types since they share the same underlying message structure.

### What happens if I specify an invalid feature name in the --features flag?

If you provide an invalid feature name to the `--features` flag, the `NewGenerator` function in [`generator/generator.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/generator.go) will fail to resolve the name to a concrete feature implementation. The generator uses the `findFeatures` function to map feature names to their corresponding generators in the `features/` directory. If a name cannot be resolved, the generation process will typically fail with an error indicating that the specified feature is unknown, preventing the generation of incomplete or broken code.

### Is protoc-gen-go-lite suitable for production use in high-performance microservices?

Yes, `protoc-gen-go-lite` is specifically designed for production environments where performance and binary size are critical concerns. The plugin generates **zero-reflection code** that eliminates the overhead of the standard protobuf runtime, making it ideal for high-throughput microservices and resource-constrained deployments like WebAssembly or embedded systems running TinyGo. The generated static methods provide deterministic performance characteristics without the memory allocations typically associated with reflection-based serialization.