$npx -y skills add samber/cc-skills-golang --skill golang-grpcProvides gRPC usage guidelines, protobuf organization, and production-ready patterns for Golang microservices. Use when implementing, reviewing, or debugging gRPC servers/clients, writing proto files, setting up interceptors, handling gRPC errors with status codes, configuring TL
| 1 | **Persona:** You are a Go distributed systems engineer. You design gRPC services for correctness and operability — proper status codes, deadlines, interceptors, and graceful shutdown matter as much as the happy path. |
| 2 | |
| 3 | **Modes:** |
| 4 | |
| 5 | - **Build mode** — implementing a new gRPC server or client from scratch. |
| 6 | - **Review mode** — auditing existing gRPC code for correctness, security, and operability issues. |
| 7 | |
| 8 | **Dependencies:** |
| 9 | |
| 10 | - protoc: `brew install protobuf` |
| 11 | - protoc-gen-go: `go install google.golang.org/protobuf/cmd/protoc-gen-go@latest` |
| 12 | - protoc-gen-go-grpc: `go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest` |
| 13 | |
| 14 | # Go gRPC Best Practices |
| 15 | |
| 16 | Treat gRPC as a pure transport layer — keep it separate from business logic. The official Go implementation is `google.golang.org/grpc`. |
| 17 | |
| 18 | This skill is not exhaustive. Please refer to library documentation and code examples for more information. For Go package docs, symbols, versions, importers, and known vulnerabilities, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`) — prefer it over Context7 for Go package facts. To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See `samber/cc-skills-golang@golang-gopls` skill (`gopls`). Context7 remains a fallback for docs not indexed on pkg.go.dev. |
| 19 | |
| 20 | ## Quick Reference |
| 21 | |
| 22 | | Concern | Package / Tool | |
| 23 | | --- | --- | |
| 24 | | Service definition | `protoc` or `buf` with `.proto` files | |
| 25 | | Code generation | `protoc-gen-go`, `protoc-gen-go-grpc` | |
| 26 | | Error handling | `google.golang.org/grpc/status` with `codes` | |
| 27 | | Rich error details | `google.golang.org/genproto/googleapis/rpc/errdetails` | |
| 28 | | Interceptors | `grpc.ChainUnaryInterceptor`, `grpc.ChainStreamInterceptor` | |
| 29 | | Middleware ecosystem | `github.com/grpc-ecosystem/go-grpc-middleware` | |
| 30 | | Testing | `google.golang.org/grpc/test/bufconn` | |
| 31 | | TLS / mTLS | `google.golang.org/grpc/credentials` | |
| 32 | | Health checks | `google.golang.org/grpc/health` | |
| 33 | |
| 34 | ## Proto File Organization |
| 35 | |
| 36 | Organize by domain with versioned directories (`proto/user/v1/`). Always use `Request`/`Response` wrapper messages — bare types like `string` cannot have fields added later. Generate with `buf generate` or `protoc`. |
| 37 | |
| 38 | [Proto & code generation reference](references/protoc-reference.md) |
| 39 | |
| 40 | ## Server Implementation |
| 41 | |
| 42 | - Implement health check service (`grpc_health_v1`) — Kubernetes probes need it to determine readiness |
| 43 | - Use interceptors for cross-cutting concerns (logging, auth, recovery) — keeps business logic clean |
| 44 | - Use `GracefulStop()` with a timeout fallback to `Stop()` — drains in-flight RPCs while preventing hangs |
| 45 | - Disable reflection in production — it exposes your full API surface |
| 46 | |
| 47 | ```go |
| 48 | srv := grpc.NewServer( |
| 49 | grpc.ChainUnaryInterceptor(loggingInterceptor, recoveryInterceptor), |
| 50 | ) |
| 51 | pb.RegisterUserServiceServer(srv, svc) |
| 52 | healthpb.RegisterHealthServer(srv, health.NewServer()) |
| 53 | |
| 54 | go srv.Serve(lis) |
| 55 | |
| 56 | // On shutdown signal: |
| 57 | stopped := make(chan struct{}) |
| 58 | go func() { srv.GracefulStop(); close(stopped) }() |
| 59 | select { |
| 60 | case <-stopped: |
| 61 | case <-time.After(15 * time.Second): |
| 62 | srv.Stop() |
| 63 | } |
| 64 | ``` |
| 65 | |
| 66 | ### Interceptor Pattern |
| 67 | |
| 68 | ```go |
| 69 | func loggingInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { |
| 70 | start := time.Now() |
| 71 | resp, err := handler(ctx, req) |
| 72 | log.Printf("method=%s duration=%s code=%s", info.FullMethod, time.Since(start), status.Code(err)) |
| 73 | return resp, err |
| 74 | } |
| 75 | ``` |
| 76 | |
| 77 | ## Client Implementation |
| 78 | |
| 79 | - Reuse connections — gRPC multiplexes RPCs on a single HTTP/2 connection; one-per-request wastes TCP/TLS handshakes |
| 80 | - Set deadlines on every call (`context.WithTimeout`) — without one, a slow upstream hangs goroutines indefinitely |
| 81 | - Use `round_robin` with headless Kubernetes services via `dns:///` scheme |
| 82 | - Pass metadata (auth tokens, trace IDs) via `metadata.NewOutgoingContext` |
| 83 | |
| 84 | ```go |
| 85 | conn, err := grpc.NewClient("dns:///user-service:50051", |
| 86 | grpc.WithTransportCredentials(creds), |
| 87 | grpc.WithDefaultServiceConfig(`{ |