Skip to main content
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
string
default:"tcp"
Network type (“tcp”, “tcp4”, “tcp6”, “unix”)
Address
string
default:":0"
Server listening address (e.g., “:9000”, “127.0.0.1:9000”)
Timeout
time.Duration
default:"1s"
Request timeout duration
Middleware
...middleware.Middleware
Unary RPC middleware (applied to all unary calls)
StreamMiddleware
...middleware.Middleware
Stream RPC middleware (applied to all streaming calls)
TLSConfig
*tls.Config
TLS configuration for secure connections
Listener
net.Listener
Custom listener (optional)
UnaryInterceptor
...grpc.UnaryServerInterceptor
Native gRPC unary interceptors
StreamInterceptor
...grpc.StreamServerInterceptor
Native gRPC stream interceptors
Options
...grpc.ServerOption
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

WithEndpoint
string
required
Target endpoint (direct address or service name with discovery)
WithTimeout
time.Duration
default:"2s"
Request timeout
WithMiddleware
...middleware.Middleware
Unary RPC middleware
WithStreamMiddleware
...middleware.Middleware
Stream RPC middleware
WithDiscovery
registry.Discovery
Service discovery implementation
WithTLSConfig
*tls.Config
TLS configuration for secure connections
WithUnaryInterceptor
...grpc.UnaryClientInterceptor
Native gRPC unary interceptors
WithStreamInterceptor
...grpc.StreamClientInterceptor
Native gRPC stream interceptors
WithOptions
...grpc.DialOption
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

Selector

Load balancing

Build docs developers (and LLMs) love