# How to Configure vtprotobuf Features (marshal+unmarshal+size+equal+clone) in protoc Commands

> Configure vtprotobuf features like marshal unmarshal size equal and clone in protoc commands with aperturerobotics protobuf go lite for efficient serialization.

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

---

**Enable vtprotobuf helpers in `protobuf-go-lite` by passing `--go-lite_opt=features=marshal+unmarshal+size+equal+clone` to your `protoc` command, which activates the corresponding code generators for high-performance serialization methods.**

The `aperturerobotics/protobuf-go-lite` repository provides a drop-in replacement for the standard `protoc-gen-go` and `protoc-gen-go-vtprotobuf` plugins. Unlike the standard toolchain, this lite generator allows you to selectively enable specific vtprotobuf features through a single `protoc` option, generating only the helper methods you need without reflection overhead.

## Understanding the vtprotobuf Feature Flags

The `protobuf-go-lite` plugin uses a feature registry system where each vtprotobuf capability registers itself under a specific name. When you configure the `features` option, the generator looks up these names and executes only the corresponding code generators.

### Available Feature Options

The following feature tokens can be combined using `+` separators in the `features` option:

- **`marshal`** – Generates `MarshalVT()`, `MarshalToVT()`, and `MarshalToSizedBufferVT()` methods for efficient serialization without reflection.
- **`marshal_strict`** – Generates strict marshaling variants that validate UTF-8 in string fields.
- **`unmarshal`** – Generates `UnmarshalVT()` methods for fast deserialization with validation.
- **`unmarshal_unsafe`** – Generates unsafe unmarshaling variants that reuse the input buffer's underlying memory.
- **`size`** – Generates `SizeVT()` methods that calculate the wire format size without allocation.
- **`equal`** – Generates `EqualVT()` and `EqualMessageVT()` methods for deep equality comparison.
- **`clone`** – Generates `CloneVT()` and `CloneMessageVT()` methods for deep copying.

### How Feature Selection Works

In [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go), the plugin parses the `features` flag and splits the value on `+` characters using `strings.Split(features, "+")`. This slice is passed to `generator.NewGenerator()`, which calls `findFeatures()` in [`generator/features.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/features.go) to resolve each token against the `defaultFeatures` registry. The registry is populated during `init()` functions in each feature package (e.g., [`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go) calls `generator.RegisterFeature("marshal", ...)`).

## Configuring vtprotobuf Features in protoc Commands

To generate Go code with specific vtprotobuf helpers, you must declare the lite plugin, specify the output directory, and pass the feature configuration option.

### Basic protoc Command Structure

```bash

# Install the plugin binary

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

# Generate with all vtprotobuf features enabled

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

```

### Breaking Down the Command Options

| Option | Purpose |
|--------|---------|
| `--plugin protoc-gen-go-lite="${GOBIN}/protoc-gen-go-lite"` | Tells `protoc` where to find the custom plugin binary. |
| `--go-lite_out=.` | Sets the destination directory for generated [`.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/.pb.go) files. |
| `--go-lite_opt=features=marshal+unmarshal+size+equal+clone` | Activates specific vtprotobuf code generators; tokens are split on `+` and looked up in the feature registry. |
| `proto/myfile.proto` | The input Protocol Buffer definition file. |

You can customize the feature combination by removing or adding tokens. For example, to generate only marshaling and sizing helpers, use `--go-lite_opt=features=marshal+size`.

## Implementation Details in protobuf-go-lite

The feature configuration system is implemented across several key files in the repository.

### Flag Parsing in main.go

In [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go), the plugin defines a `features` flag with a default value. The main function parses this flag and splits the comma-separated string (though the documentation shows `+` separation, the implementation uses `strings.Split(features, "+")` as seen in the source analysis). The resulting slice is passed to the generator constructor.

### Feature Registry and Lookup

The [`generator/features.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/features.go) file contains the `defaultFeatures` map and the `findFeatures` function. When `NewGenerator` receives the feature name slice, it calls `findFeatures` to resolve each name against registered features. The registry is populated during package initialization via `RegisterFeature` calls in each feature implementation package.

### Code Generation for Each Feature

Each vtprotobuf capability lives in its own package under `features/`:

- **[`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go)** – Registers `"marshal"` and `"marshal_strict"`, implements `GenerateFile` to create `MarshalVT` methods.
- **[`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go)** – Registers `"unmarshal"` and `"unmarshal_unsafe"`, implements `UnmarshalVT` generation.
- **[`features/size/size.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/size/size.go)** – Registers `"size"`, implements `SizeVT` calculation logic.
- **[`features/equal/equal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/equal/equal.go)** – Registers `"equal"`, implements `EqualVT` and `EqualMessageVT` methods.
- **[`features/clone/clone.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/clone/clone.go)** – Registers `"clone"`, implements `CloneVT` and `CloneMessageVT` methods.

When the generator runs, it iterates over the resolved features and calls each one's `GenerateFile` method, which walks the protobuf AST and emits the corresponding helper methods into the generated [`.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/.pb.go) files.

## Practical Code Example

When you run the `protoc` command with `--go-lite_opt=features=marshal+unmarshal+size+equal+clone`, the generated Go code for each message includes optimized methods like these:

```go
// MarshalVT serializes the message to bytes without reflection
func (m *MyMessage) MarshalVT() ([]byte, error) {
    size := m.SizeVT()
    dAtA := make([]byte, size)
    _, err := m.MarshalToSizedBufferVT(dAtA[:size])
    if err != nil {
        return nil, err
    }
    return dAtA, nil
}

// UnmarshalVT deserializes bytes into the message
func (m *MyMessage) UnmarshalVT(dAtA []byte) error {
    // Fast, zero-allocation unmarshaling logic
    return m.UnmarshalVTUnsafe(dAtA)
}

// SizeVT returns the wire format size
func (m *MyMessage) SizeVT() int {
    // Calculated without reflection
    return size
}

// EqualVT performs deep equality comparison
func (m *MyMessage) EqualVT(that *MyMessage) bool {
    // Field-by-field comparison
    return true
}

// CloneVT creates a deep copy
func (m *MyMessage) CloneVT() *MyMessage {
    // Deep copy implementation
    return cloned
}

```

These methods are generated only when their corresponding feature tokens are included in the `--go-lite_opt=features=` option.

## Summary

- **`protobuf-go-lite`** consolidates standard Go protobuf generation with vtprotobuf optimizations into a single plugin.
- **Feature selection** is controlled via the `--go-lite_opt=features=` option, accepting a `+`-separated list of feature names.
- **Available features** include `marshal`, `marshal_strict`, `unmarshal`, `unmarshal_unsafe`, `size`, `equal`, and `clone`.
- **Implementation** involves flag parsing in [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go), feature registry lookup in [`generator/features.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/features.go), and code generation in individual `features/` packages.
- **Generated code** provides zero-allocation, reflection-free methods like `MarshalVT()`, `UnmarshalVT()`, `SizeVT()`, `EqualVT()`, and `CloneVT()`.

## Frequently Asked Questions

### What is the difference between protobuf-go-lite and standard protoc-gen-go?

**`protobuf-go-lite`** replaces both the standard `protoc-gen-go` and `protoc-gen-go-vtprotobuf` plugins with a single binary. While standard `protoc-gen-go` generates basic Go structs and reflection-based marshaling, `protobuf-go-lite` generates optimized, zero-allocation helper methods (like `MarshalVT` and `UnmarshalVT`) when you enable the corresponding features via the `--go-lite_opt=features=` option.

### Can I enable only specific vtprotobuf features like just marshal and size?

Yes, you can selectively enable any combination of features by specifying only the tokens you need in the features option. For example, to generate only marshaling and sizing helpers, use `--go-lite_opt=features=marshal+size`. The plugin parses this string in [`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go) and only invokes the code generators for the specified features.

### How does protobuf-go-lite handle feature name validation?

Feature name validation occurs in [`generator/features.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/features.go) via the `findFeatures` function. When the generator receives the slice of feature names from the command line, it looks up each name against the `defaultFeatures` registry. If a feature name is not registered (for example, if you typo "marschal" instead of "marshal"), the lookup will fail and the generator will not produce code for that invalid token, ensuring only valid, implemented features are used.

### Are the generated vtprotobuf methods compatible with standard proto.Message interfaces?

The generated `MarshalVT`, `UnmarshalVT`, `SizeVT`, `EqualVT`, and `CloneVT` methods are designed to work alongside the standard `proto.Message` interface implementations, not replace them. They provide optimized alternatives to the reflection-based `proto.Marshal` and `proto.Unmarshal` functions from the standard library. Your generated structs still implement `proto.Message`, but you can call the `VT` methods directly when you need zero-allocation performance or strict unmarshaling behavior.