中文文档 | English
protoc-gen-go-flags is a Go-based Protocol Buffer compiler plugin that automatically generates command-line flag bindings for protobuf messages. It generates AddFlags methods based on protobuf message definitions, seamlessly integrating with the spf13/pflag library to provide powerful command-line argument support for your protobuf messages.
If your project meets any of the following criteria, protoc-gen-go-flags will greatly simplify your development workflow:
- ✅ Use Protocol Buffers to define configuration structures
- ✅ Need command-line argument support for CLI applications
- ✅ Want to avoid writing repetitive flag binding code manually
- ✅ Maintain consistency between configuration definitions and CLI interfaces
- ✅ Support complex nested configuration structures
Traditional Approach vs protoc-gen-go-flags:
The traditional approach requires manually writing flag bindings for each configuration field:
// Manual approach: tedious and error-prone
fs.StringVar(&config.Host, "host", "localhost", "Server host")
fs.Int32Var(&config.Port, "port", 8080, "Server port")
fs.BoolVar(&config.Verbose, "verbose", false, "Enable verbose")
// ... repeat for every fieldWith protoc-gen-go-flags:
// Auto-generated: concise and type-safe
config.AddFlags(fs)- Why Use protoc-gen-go-flags
- Features
- Quick Start
- Complete Integration Tutorial
- Usage Examples
- Supported Types
- Configuration Options
- Hierarchical Flag Organization
- FAQ
- Contributing
- License
- 🚀 Automated Code Generation: Automatically generate command-line flag bindings from protobuf messages
- 🎯 Complete Type Coverage: Support all protobuf types (scalar types, enums, repeated, map, messages, etc.)
- 🔧 Highly Configurable: Support custom flag names, shortcuts, usage text, default values, and more
- 📦 Nested Message Support: Generate hierarchical flags for nested messages
- 🏗️ Hierarchical Organization: Support hierarchical flag naming through prefixes (dot, dash, underscore, colon separators)
- 🔒 Best Practices: Generate Go-idiomatic code with support for private/public methods
- 💾 Default Value Support: Provide default value settings for all types
- 🚦 Deprecated Flags: Support deprecated and hidden flags
- 🔄 Package Aliasing: Intelligently handle package name conflicts to avoid compilation errors
Before getting started, ensure your development environment meets the following requirements:
- Go 1.18+: protoc-gen-go-flags requires Go 1.18 or higher
- Protocol Buffers Compiler (protoc): Used to compile .proto files
# macOS brew install protobuf # Ubuntu/Debian apt-get install protobuf-compiler # Or download from official releases: https://github.com/protocolbuffers/protobuf/releases
- protoc-gen-go: Go protobuf code generator
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
Install the protoc-gen-go-flags plugin:
go install github.com/kunstack/protoc-gen-go-flags@latestVerify installation:
protoc-gen-go-flags --version1. Define a protobuf message with flag options:
syntax = "proto3";
package example;
import "flags/annotations.proto";
option go_package = "github.com/example/project;example";
message Config {
string host = 1 [(flags.value).string = {
name: "host"
short: "H"
usage: "Server hostname"
}];
int32 port = 2 [(flags.value).int32 = {
name: "port"
short: "p"
usage: "Server port"
default: 8080
}];
bool verbose = 3 [(flags.value).bool = {
name: "verbose"
short: "v"
usage: "Enable verbose logging"
}];
}2. Generate code:
protoc -I. -I flags --go_out=paths=source_relative:. --flags_out=paths=source_relative:. config.proto3. Use in your application:
package main
import (
"fmt"
"os"
pb "github.com/example/project"
"github.com/spf13/pflag"
)
func main() {
var config pb.Config
// Create flag set and add flags
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
config.AddFlags(fs)
// Parse flags
fs.Parse(os.Args[1:])
// Use configuration (directly access fields)
fmt.Printf("Server: %s:%d (verbose: %v)\n",
config.Host, config.Port, config.Verbose)
}- AddFlags method: Registers configuration fields as command-line flags, allowing users to pass values via CLI arguments
- SetDefaults method: Sets default values for fields, used when no user-provided arguments are present
Usage scenarios:
- If you want default values to take effect before flag parsing, call
SetDefaults()first - If you only want to read configuration from command-line, you can use only
AddFlags() - Best practice is to combine both: provide defaults and allow user overrides
Example calls:
var config pb.Config
// Method 1: Only use AddFlags (users must provide all values)
config.AddFlags(fs)
// Method 2: Combined usage (recommended)
config.SetDefaults() // Set defaults first
config.AddFlags(fs) // Then add flags for overrides
// Method 3: Use with custom flag set
customFS := pflag.NewFlagSet("custom", pflag.ExitOnError)
config.AddFlags(customFS)This section provides a complete step-by-step tutorial to help you integrate protoc-gen-go-flags into your own projects.
Create a new Go project (or use an existing one):
mkdir myapp
cd myapp
go mod init github.com/yourname/myappInstall necessary dependencies:
# Install pflag library
go get github.com/spf13/pflag
# Install protobuf runtime
go get google.golang.org/protobuf
# Install protoc-gen-go-flags runtime library
go get github.com/kunstack/protoc-gen-go-flags/flagsCreate project structure:
myapp/
├── go.mod
├── main.go # Application entry point
└── proto/
└── config.proto # Protobuf definitionsYou need to add protoc-gen-go-flags annotation files to your project. There are two approaches:
Add the dependency in your buf.yaml:
version: v2
deps:
- buf.build/kunstack/protoc-gen-go-flags
lint:
use:
- STANDARD
breaking:
use:
- FILEThen configure code generation in buf.gen.yaml:
version: v2
plugins:
- remote: buf.build/protocolbuffers/go
out: .
opt: paths=source_relative
- local: protoc-gen-go-flags
out: .
opt: paths=source_relativeRun buf commands to update dependencies and generate code:
buf mod update
buf generateDownload the annotations.proto file from the protoc-gen-go-flags repository to your project:
mkdir -p proto/flags
curl -o proto/flags/annotations.proto \
https://raw.githubusercontent.com/kunstack/protoc-gen-go-flags/main/flags/annotations.protoUpdated project structure:
myapp/
├── go.mod
├── main.go
└── proto/
├── config.proto
└── flags/
└── annotations.protoDefine your configuration in proto/config.proto:
syntax = "proto3";
package myapp.config;
// Import flag annotations
import "flags/annotations.proto";
option go_package = "github.com/yourname/myapp/proto;config";
message ServerConfig {
// Enable empty message generation
option (flags.allow_empty) = true;
string host = 1 [(flags.value).string = {
name: "host"
short: "H"
usage: "Server host address"
default: "localhost"
}];
int32 port = 2 [(flags.value).int32 = {
name: "port"
short: "p"
usage: "Server port"
default: 8080
}];
bool debug = 3 [(flags.value).bool = {
name: "debug"
short: "d"
usage: "Enable debug mode"
}];
}Based on the option you chose in Step 2, use the appropriate command to generate code:
If you chose the Buf Schema Registry approach in Step 2, the code was already generated when you ran buf generate.
Generated files:
proto/config.pb.go- Standard protobuf Go codeproto/config.pb.flags.go- Flag binding code
If you chose the direct file copy approach in Step 2, use the protoc command to generate:
protoc \
-I./proto \
-I./proto/flags \
--go_out=. \
--go_opt=paths=source_relative \
--flags_out=. \
--flags_opt=paths=source_relative \
proto/config.protoThis generates two files:
proto/config.pb.go- Standard protobuf Go codeproto/config.pb.flags.go- Flag binding code
Use the generated code in main.go:
package main
import (
"fmt"
"os"
"github.com/spf13/pflag"
"github.com/yourname/myapp/proto"
)
func main() {
// Create configuration instance
config := &proto.ServerConfig{}
// Set defaults (optional but recommended)
config.SetDefaults()
// Create flag set
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
// Add flags
config.AddFlags(fs)
// Parse command-line arguments
if err := fs.Parse(os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err)
os.Exit(1)
}
// Use configuration
fmt.Printf("Starting server...\n")
fmt.Printf(" Host: %s\n", config.Host)
fmt.Printf(" Port: %d\n", config.Port)
fmt.Printf(" Debug: %v\n", config.Debug)
// Start your application here...
}Build the application:
go build -o myappRun and test command-line arguments:
# Use defaults
./myapp
# Output:
# Starting server...
# Host: localhost
# Port: 8080
# Debug: false
# Custom parameters
./myapp --host 0.0.0.0 --port 3000 --debug
# Output:
# Starting server...
# Host: 0.0.0.0
# Port: 3000
# Debug: true
# Use short options
./myapp -H 127.0.0.1 -p 9000 -d
# View help
./myapp --helpDepending on which option you chose, the project structure will differ slightly:
myapp/
├── go.mod
├── go.sum
├── main.go
├── buf.yaml # Buf configuration
├── buf.gen.yaml # Code generation config
├── buf.lock # Dependency lock file (generated)
├── Makefile # Optional: automation
└── proto/
├── config.proto
├── config.pb.go # Generated
└── config.pb.flags.go # GeneratedMakefile example (using buf):
.PHONY: generate build run clean
# Generate protobuf code
generate:
buf mod update
buf generate
# Build application
build: generate
go build -o bin/myapp .
# Run application
run: build
./bin/myapp
# Clean generated files
clean:
rm -f proto/*.pb.go proto/*.pb.flags.go
rm -rf bin/myapp/
├── go.mod
├── go.sum
├── main.go
├── Makefile # Optional: automation
└── proto/
├── config.proto
├── config.pb.go # Generated
├── config.pb.flags.go # Generated
└── flags/
└── annotations.protoMakefile example (using protoc):
.PHONY: generate build run clean
# Generate protobuf code
generate:
protoc \
-I./proto \
-I./proto/flags \
--go_out=. \
--go_opt=paths=source_relative \
--flags_out=. \
--flags_opt=paths=source_relative \
proto/*.proto
# Build application
build: generate
go build -o bin/myapp .
# Run application
run: build
./bin/myapp
# Clean generated files
clean:
rm -f proto/*.pb.go proto/*.pb.flags.go
rm -rf bin/Using the Makefile:
# Generate code
make generate
# Build
make build
# Run
make run
# Clean
make cleanFor complex applications, you may need nested configuration:
syntax = "proto3";
package myapp.config;
import "flags/annotations.proto";
option go_package = "github.com/yourname/myapp/proto;config";
message DatabaseConfig {
string host = 1 [(flags.value).string = {
name: "db-host"
usage: "Database host"
default: "localhost"
}];
int32 port = 2 [(flags.value).int32 = {
name: "db-port"
usage: "Database port"
default: 5432
}];
}
message AppConfig {
option (flags.allow_empty) = true;
string app_name = 1 [(flags.value).string = {
name: "app-name"
usage: "Application name"
default: "MyApp"
}];
// Nested configuration
DatabaseConfig database = 2 [(flags.value).message = {
name: "db"
nested: true
}];
}Using nested configuration:
config := &proto.AppConfig{}
config.SetDefaults()
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
config.AddFlags(fs)
fs.Parse(os.Args[1:])
fmt.Printf("App: %s\n", config.AppName)
fmt.Printf("DB: %s:%d\n", config.Database.Host, config.Database.Port)Command-line usage:
./myapp --app-name "MyService" --db-db-host db.example.com --db-db-port 3306Error message:
proto/config.proto:3:1: Import "flags/annotations.proto" was not found.
Solution:
-
Using buf approach: Ensure you ran
buf mod updateand thatbuf.yamlhas the correct dependency:deps: - buf.build/kunstack/protoc-gen-go-flags
-
Using protoc approach: Ensure the protoc command includes the correct import path:
protoc -I./proto -I./proto/flags ...
Error message:
undefined: flags.Option
undefined: types.Duration
Solution: Ensure you have installed the runtime libraries:
go get github.com/kunstack/protoc-gen-go-flags/flags
go get github.com/kunstack/protoc-gen-go-flags/types
go get github.com/kunstack/protoc-gen-go-flags/utilsThe generated code will automatically import these packages; no manual import needed.
Symptom: Command-line arguments are not being read; configuration uses zero values.
Cause: May have forgotten to call SetDefaults() or AddFlags().
Solution: Call in the correct order:
config := &proto.ServerConfig{}
config.SetDefaults() // 1. Set defaults
config.AddFlags(fs) // 2. Register flags
fs.Parse(os.Args[1:]) // 3. Parse argumentsError message:
Failure: plugin flags: not found
Solution: Ensure protoc-gen-go-flags is installed and in PATH:
# Install plugin
go install github.com/kunstack/protoc-gen-go-flags@latest
# Verify installation
which protoc-gen-go-flags
protoc-gen-go-flags --versionSymptom: Package name conflicts in generated code, such as using both wrapperspb and a custom wrapperspb package.
Solution: protoc-gen-go-flags automatically handles package name conflicts by generating aliases for conflicting packages. The generated code will automatically use aliased imports; no manual handling required.
Error message:
invalid map format: ...
Solution: Ensure you use the correct format:
- JSON format:
--config='{"key": "value"}' - STRING_TO_STRING:
--labels="key1=value1,key2=value2" - STRING_TO_INT:
--limits="cpu=1000,memory=2048"
Note: STRING_TO_INT only supports integer type values.
syntax = "proto3";
package example;
import "flags/annotations.proto";
option go_package = "github.com/example/project;example";
message ServerConfig {
option (flags.allow_empty) = true;
string host = 1 [(flags.value).string = {
name: "host"
short: "H"
usage: "Server host address"
default: "localhost"
}];
int32 port = 2 [(flags.value).int32 = {
name: "port"
short: "p"
usage: "Server port number"
default: 8080
}];
bool https = 3 [(flags.value).bool = {
name: "https"
short: "s"
usage: "Enable HTTPS"
}];
}// Generate flags with prefix
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
config.AddFlags(fs, flags.WithPrefix("server"))
fs.Parse(os.Args[1:])
// Result:
// --server.host
// --server.port
// --server.https// Use dash delimiter
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
config.AddFlags(fs,
flags.WithPrefix("server"),
flags.WithDelimiter("-"))
// Result:
// --server-host
// --server-port
// --server-httpsmessage DatabaseConfig {
string url = 1 [(flags.value).string = {
name: "database-url"
usage: "Database connection URL"
}];
}
message AppConfig {
DatabaseConfig database = 1 [(flags.value).message = {
name: "db"
nested: true
}];
}Generated flags:
--db.database-url
syntax = "proto3";
package example;
import "flags/annotations.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
option go_package = "github.com/example/project;example";
message Config {
option (flags.allow_empty) = true;
// Basic types
string host = 1 [(flags.value).string = {
name: "host"
short: "H"
usage: "Server hostname"
default: "localhost"
}];
int32 port = 2 [(flags.value).int32 = {
name: "port"
short: "p"
usage: "Server port"
default: 8080
}];
// Special types
google.protobuf.Duration timeout = 3 [(flags.value).duration = {
name: "timeout"
short: "t"
usage: "Connection timeout"
default: "30s"
}];
google.protobuf.Timestamp created = 4 [(flags.value).timestamp = {
name: "created"
usage: "Creation time"
formats: ["RFC3339", "ISO8601"]
default: "2024-01-01T00:00:00Z"
}];
// Repeated fields
repeated string servers = 5 [(flags.value).repeated.string = {
name: "servers"
short: "s"
usage: "Server addresses"
default: ["localhost:8080"]
}];
// Map fields
map<string, int32> limits = 6 [(flags.value).map = {
name: "limits"
usage: "Resource limits"
format: MAP_FORMAT_TYPE_STRING_TO_INT
default: "{\"cpu\": 1000, \"memory\": 2048}"
}];
// Nested messages
DatabaseConfig database = 7 [(flags.value).message = {
name: "database"
nested: true
}];
}protoc-gen-go-flags supports all Protocol Buffer types:
| Type | Go Type | Default Support | Repeated Support | Example |
|---|---|---|---|---|
float |
float32 |
✅ | ✅ | 3.14159 |
double |
float64 |
✅ | ✅ | 2.71828 |
int32 |
int32 |
✅ | ✅ | 42 |
int64 |
int64 |
✅ | ✅ | 9223372036854775807 |
uint32 |
uint32 |
✅ | ✅ | 1000 |
uint64 |
uint64 |
✅ | ✅ | 18446744073709551615 |
sint32 |
int32 |
✅ | ✅ | -42 |
sint64 |
int64 |
✅ | ✅ | -9223372036854775808 |
fixed32 |
uint32 |
✅ | ✅ | 8080 |
fixed64 |
uint64 |
✅ | ✅ | 3000000000 |
sfixed32 |
int32 |
✅ | ✅ | -1000 |
sfixed64 |
int64 |
✅ | ✅ | -3000000000 |
bool |
bool |
✅ | ✅ | true, false |
string |
string |
✅ | ✅ | "hello world" |
bytes |
[]byte |
✅ | ✅ | "aGVsbG8=" (base64) |
| Type | Go Type | Features | Example |
|---|---|---|---|
enum |
Enum type | Default support, repeated fields | 1 (enum value) |
google.protobuf.Duration |
*durationpb.Duration |
Default support, repeated fields | "30s", "1h" |
google.protobuf.Timestamp |
*timestamppb.Timestamp |
Multiple formats, default support, repeated fields | "2024-01-01T00:00:00Z" |
google.protobuf.StringValue |
*wrapperspb.StringValue |
Default support, repeated fields | "wrapper" |
google.protobuf.Int32Value |
*wrapperspb.Int32Value |
Default support, repeated fields | 42 |
google.protobuf.BoolValue |
*wrapperspb.BoolValue |
Default support, repeated fields | true |
| Type | Format Support | Default Support | Example |
|---|---|---|---|
repeated (all scalar types) |
- | ✅ | Slice types |
map<string, string> |
JSON, native | ✅ | {"key": "value"} |
map<string, int32> |
JSON, native | ✅ | {"key": 123} |
map<string, int64> |
JSON, native | ✅ | {"key": 456} |
Support generating hierarchical flags for nested messages, configured via the message flag type.
Message-level options control flag generation behavior for the entire message:
message MyMessage {
// Disable flag generation
option (flags.disabled) = true;
// Generate unexported flag methods (for custom wrapping)
option (flags.unexported) = true;
// Allow generating flag methods even without field configuration
option (flags.allow_empty) = true;
// Field definitions...
}| Option | Type | Description |
|---|---|---|
flags.disabled |
bool |
Skip flag generation for this message |
flags.unexported |
bool |
Generate unexported flag methods |
flags.allow_empty |
bool |
Generate methods even without field configuration |
Field-level options provide detailed configuration for individual fields:
string name = 1 [(flags.value).string = {
name: "custom-name" // Custom flag name
short: "n" // Short flag (single character)
usage: "Usage text" // Usage description
hidden: false // Hide flag (not shown in help)
deprecated: true // Mark as deprecated
deprecated_usage: "Use --new-flag instead" // Deprecation message
default: "default-value" // Default value
}];All field types support the following options:
| Option | Type | Description |
|---|---|---|
name |
string |
Custom flag name (defaults to field name) |
short |
string |
Short flag alias (single character) |
usage |
string |
Help text (required) |
hidden |
bool |
Hide flag |
deprecated |
bool |
Deprecate flag |
deprecated_usage |
string |
Deprecation message (required for deprecated flags) |
Bytes type supports encoding format selection:
bytes data = 1 [(flags.value).bytes = {
name: "data"
usage: "Binary data"
encoding: BYTES_ENCODING_TYPE_BASE64 // Or BYTES_ENCODING_TYPE_HEX
default: "aGVsbG8="
}];Supported encodings:
BYTES_ENCODING_TYPE_BASE64- Standard base64 encoding (default)BYTES_ENCODING_TYPE_HEX- Hexadecimal encoding
Timestamp type supports multiple time formats:
google.protobuf.Timestamp created_at = 1 [(flags.value).timestamp = {
name: "created-at"
usage: "Creation timestamp"
formats: ["RFC3339", "ISO8601"] // Supported formats
default: "2024-01-01T00:00:00Z"
}];Supported time formats:
| Format Name | Go Time Format Constant | Example | Description |
|---|---|---|---|
RFC3339 |
time.RFC3339 |
2024-01-01T15:04:05Z or 2024-01-01T15:04:05+08:00 |
RFC 3339 standard format (recommended) |
RFC3339Nano |
time.RFC3339Nano |
2024-01-01T15:04:05.999999999Z |
RFC 3339 with nanosecond precision |
RFC822 |
time.RFC822 |
01 Jan 24 15:04 MST |
RFC 822 format |
RFC822Z |
time.RFC822Z |
01 Jan 24 15:04 -0700 |
RFC 822 with numeric timezone |
RFC850 |
time.RFC850 |
Monday, 01-Jan-24 15:04:05 MST |
RFC 850 format |
RFC1123 |
time.RFC1123 |
Mon, 01 Jan 2024 15:04:05 MST |
RFC 1123 format |
RFC1123Z |
time.RFC1123Z |
Mon, 01 Jan 2024 15:04:05 -0700 |
RFC 1123 with numeric timezone |
ISO8601 |
Custom | 2024-01-01 |
ISO 8601 date format |
ISO8601Time |
Custom | 2024-01-01T15:04:05 |
ISO 8601 datetime format (no timezone) |
Kitchen |
time.Kitchen |
3:04PM |
Kitchen clock format |
Stamp |
time.Stamp |
Jan 1 15:04:05 |
Timestamp format |
StampMilli |
time.StampMilli |
Jan 1 15:04:05.000 |
Millisecond precision timestamp |
StampMicro |
time.StampMicro |
Jan 1 15:04:05.000000 |
Microsecond precision timestamp |
StampNano |
time.StampNano |
Jan 1 15:04:05.000000000 |
Nanosecond precision timestamp |
DateTime |
Custom | 2024-01-01 15:04:05 |
Date-time format |
DateOnly |
Custom | 2024-01-01 |
Date only format |
TimeOnly |
Custom | 15:04:05 |
Time only format |
Note:
- Besides predefined formats, you can use any valid Go time format string
- Format names support
RFC339(typo) as an alias forRFC3339for backward compatibility- In the
formatsarray, you can specify multiple formats; parsing will try them in order
google.protobuf.Duration timeout = 1 [(flags.value).duration = {
name: "timeout"
usage: "Timeout duration"
default: "30s"
}];Supported format: seconds + unit (e.g., "30s", "5m", "1h")
Map types support multiple formats, with corresponding default values based on format type:
1. JSON Format (Default)
map<string, int32> config = 1 [(flags.value).map = {
name: "config"
usage: "Configuration key-value pairs"
format: MAP_FORMAT_TYPE_JSON
default: "{\"cpu\": 1000, \"memory\": 2048}"
}];Command-line usage example:
# JSON format input
./myapp --config='{"cpu": 1000, "memory": 2048}'2. STRING_TO_STRING Format
map<string, string> labels = 1 [(flags.value).map = {
name: "labels"
usage: "Key-value labels"
format: MAP_FORMAT_TYPE_STRING_TO_STRING
default: "env=production,region=us-west"
}];Command-line usage example:
# Use comma-separated key-value pairs
./myapp --labels="env=production,region=us-west"
# Or specify multiple times (will overwrite)
./myapp --labels="env=staging" --labels="region=eu-central"3. STRING_TO_INT Format
map<string, int32> limits = 1 [(flags.value).map = {
name: "limits"
usage: "Resource limits"
format: MAP_FORMAT_TYPE_STRING_TO_INT
default: "cpu=1000,memory=2048,disk=10000"
}];Command-line usage example:
# Use comma-separated integer key-value pairs
./myapp --limits="cpu=1000,memory=2048,disk=10000"
# Single key-value pair
./myapp --limits="cpu=2000"
# Multiple specifications will merge
./myapp --limits="cpu=1000,memory=2048" --limits="disk=10000"Supported formats:
MAP_FORMAT_TYPE_JSON- JSON format (default)- Default value example:
"{\"key\": \"value\"}"
- Default value example:
MAP_FORMAT_TYPE_STRING_TO_STRING- String key-value pair format- Default value example:
"key1=value1,key2=value2" - Use commas to separate multiple key-value pairs, each connected with equals
- Default value example:
MAP_FORMAT_TYPE_STRING_TO_INT- String key to integer value format- Default value example:
"key1=123,key2=456" - Use commas to separate multiple key-value pairs, values must be integers
- Supported integer types:
int32,sint32,sfixed32,int64,sint64,sfixed64,uint32,fixed32,uint64,fixed64
- Default value example:
syntax = "proto3";
package tests;
import "flags/annotations.proto";
message Example {
repeated string servers = 1 [(flags.value).repeated.string = {
name: "servers"
usage: "Server addresses (can be specified multiple times)"
default: ["server1"]
}];
}Nested messages use the message flag type:
message NestedConfig {
string value = 1 [(flags.value).string = { name: "value" }];
}
message MainConfig {
NestedConfig nested = 1 [(flags.value).message = {
name: "nested" // Prefix name for nested message
nested: true // Enable nested flag generation
}];
}| Option | Type | Description |
|---|---|---|
name |
string |
Prefix name for nested message (defaults to field name) |
nested |
bool |
Whether to generate nested flags |
protoc-gen-go-flags supports hierarchical flag organization through WithPrefix and WithDelimiter options.
config.AddFlags(fs, flags.WithPrefix("server"))Generates: --server.host, --server.port
config.AddFlags(fs, flags.WithPrefix("server", "database"))Generates: --server.database.host, --server.database.port
config.AddFlags(fs,
flags.WithPrefix("server"),
flags.WithDelimiter("-")) // DashGenerates: --server-host, --server-port
Supported delimiters:
flags.DelimiterDot- Dot (default):server.portflags.DelimiterDash- Dash:server-portflags.DelimiterUnderscore- Underscore:server_portflags.DelimiterColon- Colon:server:port
config.AddFlags(fs,
flags.WithPrefix("Server"),
flags.WithRenamer(strings.ToLower))Generates: --server-host (converted to lowercase)
A: Follow these steps:
- Install the plugin:
go install github.com/kunstack/protoc-gen-go-flags@latest - Copy
annotations.prototo your project - Add flag annotations to your
.protofiles - Run
protocto generate code - Use the generated
AddFlags()method in your application
For detailed steps, see the Complete Integration Tutorial.
A: Use nested messages and the message flag type:
syntax = "proto3";
package tests;
import "flags/annotations.proto";
message DatabaseConfig {
string url = 1 [(flags.value).string = {
name: "url"
usage: "Database connection URL"
}];
}
message AppConfig {
DatabaseConfig database = 1 [(flags.value).message = {
name: "db"
nested: true
}];
}This generates hierarchical flags like --db-url.
A: Use options when calling AddFlags:
// With prefix
config.AddFlags(fs, flags.WithPrefix("server"))
// Generates: --server.host
// Custom delimiter
config.AddFlags(fs,
flags.WithPrefix("server"),
flags.WithDelimiter("-"))
// Generates: --server-hostA: You need to install and import the runtime library:
go get github.com/kunstack/protoc-gen-go-flags/flagsimport "github.com/kunstack/protoc-gen-go-flags/flags"A: Simply don't add flag annotations to that field. If you already added annotations, you can omit the field-level option:
string internal_field = 1; // No flag annotation; no flag will be generatedA: Use the default option in the flag annotation:
int32 port = 1 [(flags.value).int32 = {
name: "port"
usage: "Server port"
default: 8080 // Set default value
}];Then call config.SetDefaults() in your application to apply defaults.
A: protoc-gen-go-flags supports all standard protobuf types:
- Scalar types: string, int32, int64, bool, float, double, etc.
- Special types: google.protobuf.Duration, Timestamp
- Composite types: repeated (arrays), map (maps)
- Nested messages
For a detailed list, see the Supported Types section.
A: protoc-gen-go-flags focuses on command-line flag binding. For environment variable support, combine with configuration management libraries like viper:
import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
config := &proto.Config{}
fs := pflag.NewFlagSet("myapp", pflag.ExitOnError)
config.AddFlags(fs)
// Bind to viper (supports environment variables)
viper.BindPFlags(fs)
viper.AutomaticEnv()
fs.Parse(os.Args[1:])A: For .proto files, corresponding .pb.flags.go files are generated:
config.proto→config.pb.go+config.pb.flags.goserver.proto→server.pb.go+server.pb.flags.go
A: protoc-gen-go-flags is fully compatible with gRPC. You can define both gRPC services and flag configurations in the same .proto file:
protoc \
--go_out=. \
--go-grpc_out=. \
--flags_out=. \
your_service.protoContributions are welcome! If you have suggestions or find issues, please:
- Submit an issue: GitHub Issues
- Submit a pull request: Fork the project and create a PR
- Improve documentation: Help enhance documentation and examples
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
- protoc-gen-star - Code generation framework
- spf13/pflag - Command-line flag library
- Google Protocol Buffers - Data serialization protocol