Buf Commands & Project Structure

Buf commands, project structure, and code generation patterns for Protocol Buffers. Based on real-world project structure.


Installation

 1# Install buf
 2# macOS
 3brew install bufbuild/buf/buf
 4
 5# Linux
 6curl -sSL "https://github.com/bufbuild/buf/releases/latest/download/buf-$(uname -s)-$(uname -m)" -o /usr/local/bin/buf
 7chmod +x /usr/local/bin/buf
 8
 9# Windows (Scoop)
10scoop install buf
11
12# Or use Go
13go install github.com/bufbuild/buf/cmd/buf@latest
14
15# Verify installation
16buf --version

Project Structure

 1proto/
 2β”œβ”€β”€ buf.yaml              # Buf configuration
 3β”œβ”€β”€ buf.gen.yaml          # Code generation config
 4β”œβ”€β”€ buf.lock              # Dependency lock file
 5└── types/
 6    β”œβ”€β”€ core/
 7    β”‚   β”œβ”€β”€ header.proto
 8    β”‚   β”œβ”€β”€ intents.proto
 9    β”‚   └── interests.proto
10    β”œβ”€β”€ p2p/
11    β”‚   β”œβ”€β”€ addrbook.proto
12    β”‚   └── peering.proto
13    └── api/
14        β”œβ”€β”€ v1/
15        β”‚   β”œβ”€β”€ user.proto
16        β”‚   └── auth.proto
17        └── v2/
18            └── user.proto

Configuration Files

buf.yaml

 1version: v1
 2
 3# Dependencies from Buf Schema Registry
 4deps:
 5  - buf.build/protocolbuffers/wellknowntypes
 6  - buf.build/grpc-ecosystem/grpc-gateway
 7
 8# Breaking change detection
 9breaking:
10  use:
11    - FILE  # Check for breaking changes at file level
12
13# Linting rules
14lint:
15  use:
16    - DEFAULT              # Default lint rules
17    - COMMENTS             # Require comments
18    - FILE_LOWER_SNAKE_CASE  # File naming convention
19  except:
20    - COMMENT_FIELD        # Don't require field comments
21    - PACKAGE_VERSION_SUFFIX  # Allow packages without version suffix
22  
23  # Ignore specific files
24  ignore:
25    - types/test

buf.gen.yaml

 1version: v1
 2
 3# Managed mode - automatic package management
 4managed:
 5  enabled: true
 6  go_package_prefix:
 7    default: github.com/myorg/myproject/
 8    except:
 9      - buf.build/protocolbuffers/wellknowntypes
10
11# Code generation plugins
12plugins:
13  # Go
14  - plugin: go
15    out: ../
16    opt: paths=source_relative
17  
18  # gRPC Go
19  - plugin: go-grpc
20    out: ../
21    opt:
22      - paths=source_relative
23      - require_unimplemented_servers=false
24  
25  # gRPC Gateway
26  - plugin: grpc-gateway
27    out: ../
28    opt:
29      - paths=source_relative
30      - generate_unbound_methods=true
31  
32  # OpenAPI/Swagger
33  - plugin: openapiv2
34    out: ../docs
35    opt:
36      - allow_merge=true
37      - merge_file_name=api
38  
39  # TypeScript
40  - plugin: es
41    out: ../web/src/gen
42    opt:
43      - target=ts
44  
45  # Python
46  - plugin: python
47    out: ../python/gen
48  
49  # Rust
50  - plugin: rust
51    out: ../rust/gen

Basic Commands

 1# Initialize new buf project
 2buf mod init
 3
 4# Update dependencies
 5buf mod update
 6
 7# Lint proto files
 8buf lint
 9
10# Check for breaking changes
11buf breaking --against '.git#branch=main'
12
13# Generate code
14buf generate
15
16# Format proto files
17buf format -w
18
19# Build
20buf build
21
22# Export to image
23buf build -o image.bin
24
25# Export to JSON
26buf build -o image.json

Linting

 1# Lint all files
 2buf lint
 3
 4# Lint specific directory
 5buf lint types/core
 6
 7# Lint with config
 8buf lint --config buf.yaml
 9
10# List lint rules
11buf config ls-lint-rules
12
13# Check specific rules
14buf lint --error-format=json

Breaking Change Detection

 1# Check against main branch
 2buf breaking --against '.git#branch=main'
 3
 4# Check against specific commit
 5buf breaking --against '.git#commit=abc123'
 6
 7# Check against remote
 8buf breaking --against 'https://github.com/user/repo.git#branch=main'
 9
10# Check against local directory
11buf breaking --against '../old-proto'
12
13# Check against Buf Schema Registry
14buf breaking --against 'buf.build/myorg/myrepo'
15
16# Exclude specific files
17buf breaking --against '.git#branch=main' --exclude-path types/test

Code Generation

 1# Generate from local files
 2buf generate
 3
 4# Generate from specific directory
 5buf generate types/core
 6
 7# Generate with specific config
 8buf generate --template buf.gen.yaml
 9
10# Generate from remote
11buf generate buf.build/myorg/myrepo
12
13# Generate from git
14buf generate 'https://github.com/user/repo.git#branch=main,subdir=proto'

Example Proto Files

types/core/header.proto

 1syntax = "proto3";
 2
 3package types.core;
 4
 5option go_package = "github.com/myorg/myproject/types/core";
 6
 7// Type enum defines message types
 8enum Type {
 9  UNSPECIFIED_TYPE = 0;
10  MESSAGE = 1;
11  INTENT = 2;
12  INTENTS = 3;
13  INTEREST = 4;
14  INTERESTS = 5;
15  NOTIFY_INTENT = 6;
16  RESULT = 7;
17  PING = 8;
18  PONG = 9;
19  HANDSHAKE = 50;
20  PEERS = 51;
21  ADDRBOOK = 52;
22  USER_TYPES = 1000;
23}
24
25// Header is the message header
26message Header {
27  uint64 receive_timestamp = 1; // Overwritten upon reception
28  uint64 timestamp = 2;
29  Type type = 3;
30  bool want_result = 4;
31  bytes signature = 5;
32  string route = 6;
33}
34
35// Result is the optional reply from remote peer
36message Result {
37  uint64 nonce = 1;
38  uint64 error = 2;
39  string description = 3;
40}
41
42// Ping message for latency measurement
43message Ping {
44  bytes payload = 1;
45}
46
47// Pong response for latency measurement
48message Pong {
49  uint64 receive_timestamp = 1; // Local timestamp when Ping received
50  uint64 ping_timestamp = 2;    // Remote timestamp when Ping sent
51  bytes payload = 3;
52}

types/api/v1/user.proto

  1syntax = "proto3";
  2
  3package types.api.v1;
  4
  5option go_package = "github.com/myorg/myproject/types/api/v1";
  6
  7import "google/protobuf/timestamp.proto";
  8import "google/api/annotations.proto";
  9
 10// User service
 11service UserService {
 12  // Get user by ID
 13  rpc GetUser(GetUserRequest) returns (GetUserResponse) {
 14    option (google.api.http) = {
 15      get: "/v1/users/{id}"
 16    };
 17  }
 18  
 19  // List users
 20  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
 21    option (google.api.http) = {
 22      get: "/v1/users"
 23    };
 24  }
 25  
 26  // Create user
 27  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
 28    option (google.api.http) = {
 29      post: "/v1/users"
 30      body: "*"
 31    };
 32  }
 33  
 34  // Update user
 35  rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse) {
 36    option (google.api.http) = {
 37      put: "/v1/users/{id}"
 38      body: "*"
 39    };
 40  }
 41  
 42  // Delete user
 43  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) {
 44    option (google.api.http) = {
 45      delete: "/v1/users/{id}"
 46    };
 47  }
 48  
 49  // Stream user updates
 50  rpc StreamUsers(StreamUsersRequest) returns (stream User) {}
 51}
 52
 53// User message
 54message User {
 55  string id = 1;
 56  string email = 2;
 57  string name = 3;
 58  google.protobuf.Timestamp created_at = 4;
 59  google.protobuf.Timestamp updated_at = 5;
 60  repeated string roles = 6;
 61  map<string, string> metadata = 7;
 62}
 63
 64// Request/Response messages
 65message GetUserRequest {
 66  string id = 1;
 67}
 68
 69message GetUserResponse {
 70  User user = 1;
 71}
 72
 73message ListUsersRequest {
 74  int32 page_size = 1;
 75  string page_token = 2;
 76  string filter = 3;
 77}
 78
 79message ListUsersResponse {
 80  repeated User users = 1;
 81  string next_page_token = 2;
 82  int32 total_count = 3;
 83}
 84
 85message CreateUserRequest {
 86  string email = 1;
 87  string name = 2;
 88  repeated string roles = 3;
 89}
 90
 91message CreateUserResponse {
 92  User user = 1;
 93}
 94
 95message UpdateUserRequest {
 96  string id = 1;
 97  string name = 2;
 98  repeated string roles = 3;
 99}
100
101message UpdateUserResponse {
102  User user = 1;
103}
104
105message DeleteUserRequest {
106  string id = 1;
107}
108
109message DeleteUserResponse {
110  bool success = 1;
111}
112
113message StreamUsersRequest {
114  string filter = 1;
115}

Buf Schema Registry

 1# Login to Buf Schema Registry
 2buf registry login
 3
 4# Create repository
 5buf registry repository create buf.build/myorg/myrepo
 6
 7# Push to registry
 8buf push
 9
10# Pull from registry
11buf export buf.build/myorg/myrepo -o ./proto
12
13# List repositories
14buf registry repository list
15
16# Delete repository
17buf registry repository delete buf.build/myorg/myrepo

CI/CD Integration

GitHub Actions

 1name: Buf
 2
 3on:
 4  push:
 5    branches: [main]
 6  pull_request:
 7    branches: [main]
 8
 9jobs:
10  lint:
11    runs-on: ubuntu-latest
12    steps:
13      - uses: actions/checkout@v3
14      
15      - uses: bufbuild/buf-setup-action@v1
16        with:
17          github_token: ${{ secrets.GITHUB_TOKEN }}
18      
19      - name: Lint
20        run: buf lint
21        working-directory: proto
22      
23      - name: Breaking change detection
24        if: github.event_name == 'pull_request'
25        run: buf breaking --against '.git#branch=main'
26        working-directory: proto
27      
28      - name: Generate
29        run: buf generate
30        working-directory: proto
31      
32      - name: Push to Buf Schema Registry
33        if: github.ref == 'refs/heads/main'
34        run: buf push
35        working-directory: proto
36        env:
37          BUF_TOKEN: ${{ secrets.BUF_TOKEN }}

Makefile Integration

 1.PHONY: proto-lint proto-gen proto-breaking proto-format proto-clean
 2
 3# Lint proto files
 4proto-lint:
 5	cd proto && buf lint
 6
 7# Generate code
 8proto-gen:
 9	cd proto && buf generate
10
11# Check breaking changes
12proto-breaking:
13	cd proto && buf breaking --against '.git#branch=main'
14
15# Format proto files
16proto-format:
17	cd proto && buf format -w
18
19# Clean generated files
20proto-clean:
21	rm -rf types/*/types/*.pb.go
22	rm -rf types/*/types/*_grpc.pb.go
23
24# Update dependencies
25proto-update:
26	cd proto && buf mod update
27
28# Full workflow
29proto: proto-lint proto-breaking proto-gen

Best Practices

Naming Conventions

 1// βœ… Good: Clear, descriptive names
 2message UserProfile {
 3  string user_id = 1;
 4  string display_name = 2;
 5}
 6
 7// ❌ Bad: Unclear abbreviations
 8message UsrProf {
 9  string uid = 1;
10  string dn = 2;
11}

Field Numbers

 1// βœ… Good: Reserve deleted fields
 2message User {
 3  reserved 2, 3;  // Removed fields
 4  reserved "old_field", "deprecated_field";
 5  
 6  string id = 1;
 7  string name = 4;  // New field
 8}
 9
10// ❌ Bad: Reusing field numbers
11message User {
12  string id = 1;
13  string name = 2;  // Was email before, now name
14}

Enums

 1// βœ… Good: Zero value is UNSPECIFIED
 2enum Status {
 3  STATUS_UNSPECIFIED = 0;
 4  STATUS_ACTIVE = 1;
 5  STATUS_INACTIVE = 2;
 6}
 7
 8// ❌ Bad: Zero value has meaning
 9enum Status {
10  ACTIVE = 0;  // Zero should be unspecified
11  INACTIVE = 1;
12}

Versioning

1// βœ… Good: Version in package name
2package myapp.api.v1;
3
4// βœ… Good: Version in service name for breaking changes
5service UserServiceV2 {
6  rpc GetUser(GetUserRequest) returns (GetUserResponse);
7}

Troubleshooting

 1# Clear buf cache
 2rm -rf ~/.cache/buf
 3
 4# Verbose output
 5buf generate --debug
 6
 7# Check dependencies
 8buf mod ls-deps
 9
10# Validate configuration
11buf config ls-lint-rules
12buf config ls-breaking-rules
13
14# Check proto syntax
15protoc --proto_path=. --descriptor_set_out=/dev/null types/**/*.proto

Related Snippets