Kratos provides a production-ready gRPC transport built on top of Google’s gRPC-Go library with support for middleware, service discovery, health checks, and reflection.
gRPC Server
Creating a Server
transport/grpc/server.go:154-203
import (
" github.com/go-kratos/kratos/v2/transport/grpc "
)
grpcSrv := grpc . NewServer (
grpc . Address ( ":9000" ),
grpc . Timeout ( 1 * time . Second ),
grpc . Middleware (
recovery . Recovery (),
logging . Server (),
),
)
Server Options
Network type (“tcp”, “tcp4”, “tcp6”, “unix”)
Server listening address (e.g., “:9000”, “127.0.0.1:9000”)
Timeout
time.Duration
default: "1s"
Request timeout duration
Unary RPC middleware (applied to all unary calls)
Stream RPC middleware (applied to all streaming calls)
TLS configuration for secure connections
Custom listener (optional)
UnaryInterceptor
...grpc.UnaryServerInterceptor
Native gRPC unary interceptors
StreamInterceptor
...grpc.StreamServerInterceptor
Native gRPC stream interceptors
Additional native gRPC server options
Registering Services
import (
pb " your-project/api/helloworld/v1 "
)
// Register your gRPC service
type GreeterService struct {
pb . UnimplementedGreeterServer
}
func ( s * GreeterService ) SayHello ( ctx context . Context , req * pb . HelloRequest ) ( * pb . HelloReply , error ) {
return & pb . HelloReply {
Message : "Hello " + req . Name ,
}, nil
}
grpcSrv := grpc . NewServer ( grpc . Address ( ":9000" ))
pb . RegisterGreeterServer ( grpcSrv , & GreeterService {})
Selective Middleware
Apply middleware to specific services or methods:
transport/grpc/server.go:205-212
// Use middleware with selector patterns:
// - '/*' - all services
// - '/helloworld.v1.Greeter/*' - all methods in service
// - '/helloworld.v1.Greeter/SayHello' - specific method
grpcSrv . Use ( "/helloworld.v1.Greeter/*" ,
auth . JWT ( jwtSecret ),
ratelimit . Server (),
)
Built-in Services
Kratos automatically registers:
Health Check gRPC health checking protocol
Reflection Server reflection for tools like grpcurl
Admin Administrative services
// Disable reflection
grpcSrv := grpc . NewServer (
grpc . DisableReflection (),
)
// Use custom health check
grpcSrv := grpc . NewServer (
grpc . CustomHealth (),
)
Server Lifecycle
transport/grpc/server.go:226-257
func main () {
grpcSrv := grpc . NewServer (
grpc . Address ( ":9000" ),
)
// Register services
pb . RegisterGreeterServer ( grpcSrv , & GreeterService {})
// Start server
go func () {
if err := grpcSrv . Start ( context . Background ()); err != nil {
log . Fatal ( err )
}
}()
// Graceful shutdown
quit := make ( chan os . Signal , 1 )
signal . Notify ( quit , syscall . SIGINT , syscall . SIGTERM )
<- quit
ctx , cancel := context . WithTimeout ( context . Background (), 5 * time . Second )
defer cancel ()
if err := grpcSrv . Stop ( ctx ); err != nil {
log . Error ( "Server forced to shutdown:" , err )
}
}
gRPC Client
Creating a Client
transport/grpc/client.go:154-215
import (
" github.com/go-kratos/kratos/v2/transport/grpc "
)
// Create connection
conn , err := grpc . DialInsecure (
context . Background (),
grpc . WithEndpoint ( "127.0.0.1:9000" ),
grpc . WithTimeout ( 2 * time . Second ),
grpc . WithMiddleware (
logging . Client (),
),
)
if err != nil {
log . Fatal ( err )
}
defer conn . Close ()
// Create service client
client := pb . NewGreeterClient ( conn )
Client Options
Target endpoint (direct address or service name with discovery)
WithTimeout
time.Duration
default: "2s"
Request timeout
Service discovery implementation
TLS configuration for secure connections
WithUnaryInterceptor
...grpc.UnaryClientInterceptor
Native gRPC unary interceptors
WithStreamInterceptor
...grpc.StreamClientInterceptor
Native gRPC stream interceptors
Additional native gRPC dial options
Secure vs Insecure
// Insecure connection (no TLS)
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "127.0.0.1:9000" ),
)
// Secure connection (with TLS)
conn , err := grpc . Dial (
ctx ,
grpc . WithEndpoint ( "example.com:443" ),
grpc . WithTLSConfig ( & tls . Config {
// TLS configuration
}),
)
Making Requests
reply , err := client . SayHello ( ctx , & pb . HelloRequest {
Name : "Kratos" ,
})
if err != nil {
log . Error ( err )
return
}
log . Infof ( "Response: %s " , reply . Message )
Service Discovery Integration
transport/grpc/client.go:194-203
import (
" github.com/go-kratos/kratos/v2/registry "
" github.com/go-kratos/kratos/contrib/registry/consul/v2 "
)
// Create discovery client
dis := consul . New ( consulClient )
// Create gRPC client with discovery
conn , err := grpc . DialInsecure (
context . Background (),
grpc . WithEndpoint ( "discovery:///my-service" ),
grpc . WithDiscovery ( dis ),
)
Load Balancing
Kratos automatically configures load balancing with service discovery:
// Uses Weighted Round Robin (WRR) by default
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "discovery:///my-service" ),
grpc . WithDiscovery ( dis ),
)
// Automatic health checking
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "discovery:///my-service" ),
grpc . WithDiscovery ( dis ),
grpc . WithHealthCheck ( true ), // enabled by default
)
Interceptors
Unary Interceptor
transport/grpc/client.go:217-249
func myUnaryInterceptor ( ctx context . Context , method string , req , reply interface {},
cc * grpc . ClientConn , invoker grpc . UnaryInvoker , opts ... grpc . CallOption ) error {
log . Infof ( "Calling method: %s " , method )
// Call the RPC
err := invoker ( ctx , method , req , reply , cc , opts ... )
log . Infof ( "Method %s completed" , method )
return err
}
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "127.0.0.1:9000" ),
grpc . WithUnaryInterceptor ( myUnaryInterceptor ),
)
Stream Interceptor
transport/grpc/client.go:299-333
func myStreamInterceptor ( ctx context . Context , desc * grpc . StreamDesc ,
cc * grpc . ClientConn , method string , streamer grpc . Streamer ,
opts ... grpc . CallOption ) ( grpc . ClientStream , error ) {
log . Infof ( "Starting stream: %s " , method )
return streamer ( ctx , desc , cc , method , opts ... )
}
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "127.0.0.1:9000" ),
grpc . WithStreamInterceptor ( myStreamInterceptor ),
)
Advanced Features
Subset Selection
Limit the number of nodes selected from service discovery:
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "discovery:///my-service" ),
grpc . WithDiscovery ( dis ),
grpc . WithSubset ( 10 ), // Select max 10 nodes
)
Node Filters
Filter service instances based on criteria:
import " github.com/go-kratos/kratos/v2/selector "
// Filter by version
versionFilter := func ( ctx context . Context , nodes [] selector . Node ) [] selector . Node {
filtered := [] selector . Node {}
for _ , node := range nodes {
if node . Version () == "v1.0.0" {
filtered = append ( filtered , node )
}
}
return filtered
}
conn , err := grpc . DialInsecure (
ctx ,
grpc . WithEndpoint ( "discovery:///my-service" ),
grpc . WithDiscovery ( dis ),
grpc . WithNodeFilter ( versionFilter ),
)
Best Practices
Reuse gRPC connections across multiple requests. Creating a connection is expensive.
Use GracefulStop() (via Stop()) to allow in-flight RPCs to complete.
Always pass context through the call chain for cancellation and deadlines.
Use discovery in production instead of hardcoding endpoints for better resilience.
Use built-in health checking for better load balancing decisions.
Transport Transport layer abstractions
Middleware Middleware system
Registry Service discovery