PluginBench
Skill
Pass
Audit score 90

golang-grpc

samber/cc-skills-golang

gRPC usage guidelines, protobuf organization, and production-ready patterns for Go microservices.

What is golang-grpc?

Provides best practices for implementing gRPC servers and clients in Go, including proto file organization, interceptors, error handling with status codes, TLS/mTLS configuration, streaming patterns, and testing strategies. Use when building, reviewing, or debugging gRPC services and handling distributed communication in Go.

  • Design gRPC servers with health checks, graceful shutdown, and cross-cutting interceptors
  • Implement gRPC clients with connection reuse, deadlines, load balancing, and retry policies
  • Organize proto files by domain with versioned directories and generate code with protoc/buf
  • Handle errors with specific gRPC status codes and rich error details for client decision-making
  • Configure TLS/mTLS for production security and implement authentication via PerRPCCredentials
  • Test gRPC services in-memory using bufconn without network overhead

How to install golang-grpc

npx skills add https://github.com/samber/cc-skills-golang --skill golang-grpc
Prerequisites
  • Go installed and configured
  • protoc compiler: brew install protobuf
  • protoc-gen-go: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
  • protoc-gen-go-grpc: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Claude Code
Cursor
Windsurf
Cline

How to use golang-grpc

  1. 1.Define your service API in .proto files organized by domain (e.g., proto/user/v1/)
  2. 2.Generate Go code using protoc or buf with protoc-gen-go and protoc-gen-go-grpc plugins
  3. 3.Implement your service handler, registering it with grpc.NewServer() and adding interceptors for logging/auth/recovery
  4. 4.Implement a health check service (grpc_health_v1) for Kubernetes readiness probes
  5. 5.Return errors using status.Error() with specific gRPC codes (NotFound, InvalidArgument, etc.) instead of raw errors
  6. 6.Set up client connections with connection reuse, deadlines via context.WithTimeout(), and load balancing policies
  7. 7.Add TLS/mTLS credentials via grpc.WithTransportCredentials() for production deployments
  8. 8.Test using bufconn for in-memory connections and verify error codes in test scenarios

Use cases

Good for
  • Building a new gRPC microservice from scratch with proper error handling and interceptors
  • Auditing existing gRPC code for security, operability, and status code correctness
  • Setting up client-side load balancing and retry policies for resilient service-to-service calls
  • Implementing streaming RPCs for large datasets or real-time bidirectional communication
  • Configuring mTLS for service mesh integration or direct service-to-service authentication
Who it's for
  • Go backend engineers building distributed systems
  • DevOps/SRE teams reviewing gRPC service implementations for production readiness
  • Microservices architects designing service-to-service communication patterns
  • Teams migrating from REST to gRPC or integrating with existing gRPC infrastructure

golang-grpc FAQ

When should I use gRPC vs REST?

Use gRPC for service-to-service communication where performance, multiplexing, and streaming matter. REST is better for public APIs and browser clients. gRPC excels in microservices with high request volume and complex data types.

What gRPC status code should I return for a missing resource?

Return codes.NotFound with status.Errorf(codes.NotFound, ...). This tells clients the error is permanent and not worth retrying. Use codes.Unavailable only for transient issues.

Do I need to create a new gRPC connection for each request?

No — reuse a single connection. gRPC multiplexes many RPCs over one HTTP/2 connection. Creating new connections wastes TCP/TLS handshakes and goroutines. Store the connection and reuse it.

How do I test gRPC services without a real network?

Use google.golang.org/grpc/test/bufconn for in-memory connections. It exercises the full gRPC stack (serialization, interceptors, metadata) without network overhead and is ideal for unit tests.

Should I enable gRPC reflection in production?

No — disable reflection in production. It exposes your entire API surface and service definitions to any client. Enable it only in development for debugging tools like grpcurl.

Full instructions (SKILL.md)

Source of truth, from samber/cc-skills-golang.


name: golang-grpc description: "Provides 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 TLS/mTLS, testing with bufconn, or working with streaming RPCs." user-invocable: true license: MIT compatibility: Designed for Claude Code or similar AI coding agents, and for projects using Golang. metadata: author: samber version: "1.1.5" openclaw: emoji: "🌐" homepage: https://github.com/samber/cc-skills-golang requires: bins: - go - protoc install: - kind: brew formula: protobuf bins: [protoc] allowed-tools: Read Edit Write Glob Grep Bash(go:) Bash(golangci-lint:) Bash(git:) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(protoc:) AskUserQuestion

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.

Modes:

  • Build mode — implementing a new gRPC server or client from scratch.
  • Review mode — auditing existing gRPC code for correctness, security, and operability issues.

Dependencies:

  • protoc: brew install protobuf
  • protoc-gen-go: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
  • protoc-gen-go-grpc: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Go gRPC Best Practices

Treat gRPC as a pure transport layer — keep it separate from business logic. The official Go implementation is google.golang.org/grpc.

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform. For Go package docs, versions, symbols, and known vulnerabilities, → See samber/cc-skills-golang@golang-pkg-go-dev skill.

Quick Reference

ConcernPackage / Tool
Service definitionprotoc or buf with .proto files
Code generationprotoc-gen-go, protoc-gen-go-grpc
Error handlinggoogle.golang.org/grpc/status with codes
Rich error detailsgoogle.golang.org/genproto/googleapis/rpc/errdetails
Interceptorsgrpc.ChainUnaryInterceptor, grpc.ChainStreamInterceptor
Middleware ecosystemgithub.com/grpc-ecosystem/go-grpc-middleware
Testinggoogle.golang.org/grpc/test/bufconn
TLS / mTLSgoogle.golang.org/grpc/credentials
Health checksgoogle.golang.org/grpc/health

Proto File Organization

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.

Proto & code generation reference

Server Implementation

  • Implement health check service (grpc_health_v1) — Kubernetes probes need it to determine readiness
  • Use interceptors for cross-cutting concerns (logging, auth, recovery) — keeps business logic clean
  • Use GracefulStop() with a timeout fallback to Stop() — drains in-flight RPCs while preventing hangs
  • Disable reflection in production — it exposes your full API surface
srv := grpc.NewServer(
    grpc.ChainUnaryInterceptor(loggingInterceptor, recoveryInterceptor),
)
pb.RegisterUserServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, health.NewServer())

go srv.Serve(lis)

// On shutdown signal:
stopped := make(chan struct{})
go func() { srv.GracefulStop(); close(stopped) }()
select {
case <-stopped:
case <-time.After(15 * time.Second):
    srv.Stop()
}

Interceptor Pattern

func loggingInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
    start := time.Now()
    resp, err := handler(ctx, req)
    log.Printf("method=%s duration=%s code=%s", info.FullMethod, time.Since(start), status.Code(err))
    return resp, err
}

Client Implementation

  • Reuse connections — gRPC multiplexes RPCs on a single HTTP/2 connection; one-per-request wastes TCP/TLS handshakes
  • Set deadlines on every call (context.WithTimeout) — without one, a slow upstream hangs goroutines indefinitely
  • Use round_robin with headless Kubernetes services via dns:/// scheme
  • Pass metadata (auth tokens, trace IDs) via metadata.NewOutgoingContext
conn, err := grpc.NewClient("dns:///user-service:50051",
    grpc.WithTransportCredentials(creds),
    grpc.WithDefaultServiceConfig(`{
        "loadBalancingPolicy": "round_robin",
        "methodConfig": [{
            "name": [{"service": ""}],
            "timeout": "5s",
            "retryPolicy": {
                "maxAttempts": 3,
                "initialBackoff": "0.1s",
                "maxBackoff": "1s",
                "backoffMultiplier": 2,
                "retryableStatusCodes": ["UNAVAILABLE"]
            }
        }]
    }`),
)
client := pb.NewUserServiceClient(conn)

Error Handling

Always return gRPC errors using status.Error with a specific code — a raw error becomes codes.Unknown, telling the client nothing actionable. Clients use codes to decide retry vs fail-fast vs degrade.

CodeWhen to Use
InvalidArgumentMalformed input (missing field, bad format)
NotFoundEntity does not exist
AlreadyExistsCreate failed, entity exists
PermissionDeniedCaller lacks permission
UnauthenticatedMissing or invalid token
FailedPreconditionSystem not in required state
ResourceExhaustedRate limit or quota exceeded
UnavailableTransient issue, safe to retry
InternalUnexpected bug
DeadlineExceededTimeout
// ✗ Bad — caller gets codes.Unknown, can't decide whether to retry
return nil, fmt.Errorf("user not found")

// ✓ Good — specific code lets clients act appropriately
if errors.Is(err, ErrNotFound) {
    return nil, status.Errorf(codes.NotFound, "user %q not found", req.UserId)
}
return nil, status.Errorf(codes.Internal, "lookup failed: %v", err)

For field-level validation errors, attach errdetails.BadRequest via status.WithDetails.

Streaming

PatternUse Case
Server streamingServer sends a sequence (log tailing, result sets)
Client streamingClient sends a sequence, server responds once (file upload, batch)
BidirectionalBoth send independently (chat, real-time sync)

Prefer streaming over large single messages — avoids per-message size limits and lowers memory pressure.

func (s *server) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error {
    for _, u := range users {
        if err := stream.Send(u); err != nil {
            return err
        }
    }
    return nil
}

Testing

Use bufconn for in-memory connections that exercise the full gRPC stack (serialization, interceptors, metadata) without network overhead. Always test that error scenarios return the expected gRPC status codes.

Testing patterns and examples

Security

  • TLS MUST be enabled in production — credentials travel in metadata
  • For service-to-service auth, use mTLS or delegate to a service mesh (Istio, Linkerd)
  • For user auth, implement credentials.PerRPCCredentials and validate tokens in an auth interceptor
  • Reflection SHOULD be disabled in production to prevent API discovery

Performance

SettingPurposeTypical Value
keepalive.ServerParameters.TimePing interval for idle connections30s
keepalive.ServerParameters.TimeoutPing ack timeout10s
grpc.MaxRecvMsgSizeOverride 4 MB default for large payloads16 MB
Connection poolingMultiple conns for high-load streaming4 connections

Most services do not need connection pooling — profile before adding complexity.

Common Mistakes

MistakeFix
Returning raw errorBecomes codes.Unknown — client can't decide whether to retry. Use status.Errorf with a specific code
No deadline on client callsSlow upstream hangs indefinitely. Always context.WithTimeout
New connection per requestWastes TCP/TLS handshakes. Create once, reuse — HTTP/2 multiplexes RPCs
Reflection enabled in productionLets attackers enumerate every method. Enable only in dev/staging
codes.Internal for all errorsWrong codes break client retry logic. Unavailable triggers retry; InvalidArgument does not
Bare types as RPC argumentsCan't add fields to string. Wrapper messages allow backwards-compatible evolution
Missing health check serviceKubernetes can't determine readiness, kills pods during deployments
Ignoring context cancellationLong operations continue after caller gave up. Check ctx.Err()

Cross-References

  • → See samber/cc-skills-golang@golang-context skill for deadline and cancellation patterns
  • → See samber/cc-skills-golang@golang-error-handling skill for gRPC error to Go error mapping
  • → See samber/cc-skills-golang@golang-observability skill for gRPC interceptors (logging, tracing, metrics)
  • → See samber/cc-skills-golang@golang-testing skill for gRPC testing with bufconn