# protobuf-go-lite and the StaRPC Ecosystem: Building Lightweight RPCs Without Reflection

> Discover how protobuf-go-lite powers the StaRPC ecosystem for ultra-lightweight RPCs. Build efficient applications with static, reflection-free message handling and reduced overhead.

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

---

**protobuf-go-lite serves as the core protobuf code-generation and runtime library for the StaRPC ecosystem, providing static, reflection-free message handling that enables lightweight RPC implementations with minimal binary size and CPU overhead.**

The `aperturerobotics/protobuf-go-lite` repository delivers a specialized Protocol Buffers compiler plugin and runtime designed for performance-critical applications. It generates Go code capable of marshaling, unmarshaling, sizing, cloning, and comparing protobuf messages without using Go reflection. This foundational message layer powers the StaRPC ecosystem, which implements lightweight RPC services in both Go and TypeScript by combining these efficient serialization primitives with transport logic.

## The Architectural Relationship

The relationship between `protobuf-go-lite` and StaRPC represents a clear separation of concerns: `protobuf-go-lite` handles the **message serialization layer**, while StaRPC provides the **transport, service definition, and client/server scaffolding**.

### Static, Reflection-Free Message Handling

At the core of `protobuf-go-lite` is a code generator that produces methods like `MarshalVT()`, `UnmarshalVT()`, `SizeVT()`, and `EqualVT()` directly on generated Go structs. These implementations reside in [`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go) and [`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go), utilizing static type information rather than the `reflect` package. This approach yields significantly smaller binary sizes and reduces CPU/memory overhead compared to standard protobuf implementations, which is essential for lightweight RPC scenarios.

### StaRPC's Transport Layer

According to the repository's [`README.md`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/README.md) (lines 29-33), the ecosystem description states: *"Lightweight Protobuf 3 RPCs are implemented in **[StaRPC]** for Go and TypeScript."* StaRPC imports the message types generated by `protobuf-go-lite` and uses them to encode and decode RPC payloads over the wire, while handling connection management, service dispatch, and streaming semantics.

## Generating Code with protoc-gen-go-lite

To utilize `protobuf-go-lite` within the StaRPC ecosystem, you first define your service in a `.proto` file and generate Go code using the `protoc-gen-go-lite` plugin.

Define a service interface:

```proto
syntax = "proto3";

package example;

message Request {
  string payload = 1;
}

message Response {
  string result = 1;
}

service Echo {
  rpc Call(Request) returns (Response);
}

```

Install the plugin and generate the code:

```bash

# Install the plugin (once)

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

# Run protoc with the lite plugin

protoc --go-lite_out=. --go-lite_opt=features=marshal+unmarshal+size+equal+clone \
       --go-lite_opt=buildTag=lite example.proto

```

The generator logic 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 [`generator/generator.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/generator.go) processes these options to emit [`example.pb.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/example.pb.go) containing the optimized methods. The `features` flag selects which capabilities to include, while `buildTag=lite` ensures the generated code compiles with appropriate build constraints.

## Implementing a StaRPC Service

Once generated, the message types integrate seamlessly with StaRPC's server and client APIs. The generated code includes registration stubs and client constructors that StaRPC uses to wire up the RPC handlers.

### Server Implementation

Create a server using the generated registration functions:

```go
package main

import (
	"context"
	"log"
	"net"

	starpc "github.com/aperturerobotics/starpc/go"
	pb "myproject/example" // generated by protobuf-go-lite
)

type echoService struct{}

func (s *echoService) Call(ctx context.Context, req *pb.Request) (*pb.Response, error) {
	return &pb.Response{Result: "echo: " + req.Payload}, nil
}

func main() {
	srv := starpc.NewServer()
	pb.RegisterEchoServer(srv, &echoService{})

	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatalf("listen: %v", err)
	}
	if err := srv.Serve(l); err != nil {
		log.Fatalf("serve: %v", err)
	}
}

```

### Client Implementation

Consume the service using the generated client constructor:

```go
package main

import (
	"context"
	"log"

	starpc "github.com/aperturerobotics/starpc/go"
	pb "myproject/example"
)

func main() {
	conn, err := starpc.Dial("tcp", "localhost:8080")
	if err != nil {
		log.Fatalf("dial: %v", err)
	}
	client := pb.NewEchoClient(conn)

	resp, err := client.Call(context.Background(), &pb.Request{Payload: "hello"})
	if err != nil {
		log.Fatalf("rpc error: %v", err)
	}
	log.Println("Response:", resp.Result)
}

```

In this flow, `protobuf-go-lite` provides the only protobuf-specific code through the generated `*.pb.go` file and its helper methods. StaRPC consumes these types via [`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go) and [`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go) to handle payload encoding, while [`features/json/message.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/json/message.go) provides optional JSON serialization helpers for REST-bridge scenarios.

## Key Source Files in the Repository

The following files in `aperturerobotics/protobuf-go-lite` define the static generation system that StaRPC consumes:

- **[`cmd/protoc-gen-go-lite/main.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/cmd/protoc-gen-go-lite/main.go)** – The protoc plugin entry point that parses options and invokes the generator
- **[`generator/generator.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/generator/generator.go)** – Core orchestration logic for feature selection and file emission
- **[`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go)** – Implements `MarshalVT*` methods for RPC payload encoding
- **[`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go)** – Implements `UnmarshalVT*` methods for RPC payload decoding
- **[`features/json/message.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/json/message.go)** – JSON (de)serialization helpers for REST-compatible endpoints
- **[`internal/version/version.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/internal/version/version.go)** – Version reporting used by the CLI tool

## Summary

- **protobuf-go-lite** generates reflection-free Go code for protobuf message handling, located in `aperturerobotics/protobuf-go-lite`
- **StaRPC** builds upon this foundation to provide lightweight RPC transport and service scaffolding for Go and TypeScript
- The generator creates methods like `MarshalVT()` and `UnmarshalVT()` (defined in [`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go) and [`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go)) that operate without reflection
- Use `protoc-gen-go-lite` with flags `--go-lite_opt=features=marshal+unmarshal+size+equal+clone` to generate StaRPC-compatible message types
- The separation of message layer (protobuf-go-lite) and transport layer (StaRPC) enables high-performance, low-overhead RPC systems

## Frequently Asked Questions

### What is the primary advantage of using protobuf-go-lite over standard Go protobuf libraries?

**protobuf-go-lite** eliminates Go reflection from the serialization path, generating static methods like `MarshalVT()` and `SizeVT()` that directly access struct fields. According to the source code in [`features/marshal/marshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/marshal/marshal.go) and [`features/unmarshal/unmarshal.go`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/features/unmarshal/unmarshal.go), this produces smaller binaries and reduces CPU and memory overhead compared to the standard library's reflection-based approach, making it ideal for resource-constrained RPC services.

### How does StaRPC utilize protobuf-go-lite generated code?

StaRPC imports the message types generated by `protobuf-go-lite` and uses them as the wire format for RPC calls. While `protobuf-go-lite` handles the encoding and decoding via methods like `UnmarshalVT()`, StaRPC manages the transport layer, connection pooling, and service routing. The [`README.md`](https://github.com/aperturerobotics/protobuf-go-lite/blob/main/README.md) explicitly positions StaRPC as the ecosystem that implements lightweight Protobuf 3 RPCs using this library.

### Can protobuf-go-lite be used independently of StaRPC?

Yes. `protobuf-go-lite` functions as a standalone protobuf code generator and runtime. You can use the generated message types with any transport system or store them directly. However, the library is optimized for and commonly paired with StaRPC to form a complete lightweight RPC stack.

### Which generator features should be enabled for full StaRPC compatibility?

Enable the complete feature set using `--go-lite_opt=features=marshal+unmarshal+size+equal+clone`. This ensures the generated code includes `MarshalVT()` for encoding, `UnmarshalVT()` for decoding, `SizeVT()` for buffer pre-allocation, and equality/comparison methods. These methods are invoked by StaRPC during request/response processing to ensure efficient wire protocol handling.