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
- Google Protobuf Packages
Useful Google protobuf packages for APIs, gRPC, and common patterns. googleapis β¦ - Protobuf Well-Known Types
Google's standard protobuf library includes many useful well-known types. Import β¦