# What Are the Key Differences Between gRPC and HTTP Server Implementations in Kratos?

> Explore Kratos gRPC vs HTTP server differences. Understand routing, middleware patterns, and protocol features for robust Go applications. Learn key implementation distinctions.

- Repository: [Kratos/kratos](https://github.com/go-kratos/kratos)
- Tags: deep-dive
- Published: 2026-03-02

---

**The HTTP server in Kratos wraps Go's standard `net/http` with a gorilla/mux router and filter-based middleware, while the gRPC server wraps Google's `grpc` library with interceptors and built-in health/reflection services—both implementing the same `transport.Server` interface but differing in routing, middleware patterns, and protocol-specific features.**

Kratos provides unified abstractions for microservice transports in the `go-kratos/kratos` repository, allowing developers to expose services over HTTP or gRPC using similar APIs. While both transports implement the `transport.Server` and `transport.Endpointer` interfaces defined in [`transport/transport.go`](https://github.com/go-kratos/kratos/blob/main/transport/transport.go), their internal implementations in [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go) and [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go) reflect fundamental differences in how each protocol handles routing, middleware, and metadata.

## Architecture and Underlying Stack

### HTTP Server Foundation

The HTTP transport is built on Go's standard library `net/http` server. In [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go), the `Server` struct embeds `*http.Server` and adds a `*mux.Router` from the gorilla/mux package for path-based routing. This design provides full HTTP/1.1 and HTTP/2 support with traditional REST semantics, where routes are registered via URL patterns and HTTP methods.

### gRPC Server Foundation

Conversely, the gRPC transport in [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go) wraps `*grpc.Server` from `google.golang.org/grpc`. This implementation leverages HTTP/2 framing and Protocol Buffers, where service methods are identified by fully-qualified protobuf names rather than URL paths. The gRPC server requires generated code from `.proto` files to register service handlers, eliminating the need for a traditional router implementation.

## Routing and Request Handling

### HTTP Router and Filters

The HTTP server exposes a sophisticated routing layer through gorilla/mux, supporting path templates, query parameters, and subrouters. Request processing utilizes a **filter chain** (`FilterFunc`) that wraps `http.Handler` interfaces. As implemented in [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go), filters are composed into a `FilterChain` allowing request-level preprocessing before reaching service handlers.

### gRPC Method Matching

The gRPC implementation has no router abstraction. Instead, method routing is handled internally by the gRPC library based on the service definition. Middleware application relies on **matchers** that target specific service names or method patterns. This distinction means gRPC servers cannot use path-based routing logic; all endpoint resolution happens through protobuf service descriptors.

## Middleware and Interceptor Patterns

### HTTP Middleware Architecture

HTTP middleware in Kratos operates through two distinct layers. **Service-level middleware** is applied via `Server.Use()`, utilizing `middleware.Matcher` to conditionally execute logic. **Request-level filters** provide lower-level access to the raw HTTP request and response writers, enabling custom header manipulation and request validation before business logic executes.

### gRPC Interceptor Pipelines

The gRPC server separates middleware into **unary** and **stream** variants. Unary interceptors handle single request-response calls via `unaryServerInterceptor`, while stream interceptors manage bidirectional streaming through `streamServerInterceptor`. As defined in [`transport/grpc/interceptor.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/interceptor.go), these interceptors inject the Kratos transport context and handle metadata extraction differently than HTTP headers.

## Built-in Services and Observability

### gRPC Health and Reflection

The gRPC server automatically registers the **gRPC health service** (`grpc_health_v1.RegisterHealthServer`) unless disabled via `CustomHealth`. It also enables **reflection** by default through `reflection.Register`, allowing tools like `grpcurl` to introspect service definitions. Additionally, the gRPC transport registers an **admin service** (`admin.Register`) for runtime debugging, features absent from the HTTP implementation.

### HTTP Service Discovery

The HTTP server generates endpoints using `endpoint.NewEndpoint` with the scheme `"http"` and includes TLS state detection (`s.tlsConf != nil`). Unlike gRPC, HTTP requires manual implementation of health check endpoints and lacks automatic service reflection capabilities, placing more responsibility on application developers to expose observability endpoints.

## TLS Configuration and Security

Both transports support mutual TLS, but configuration differs significantly. The HTTP server attaches TLS directly to the embedded `http.Server.TLSConfig` field. In contrast, the gRPC server applies TLS as **server credentials** via `grpc.Creds(credentials.NewTLS(s.tlsConf))`, converting the standard `*tls.Config` into gRPC's credential system before server initialization.

## Practical Implementation Examples

### Creating an HTTP Server with Filters

The following example demonstrates the HTTP server with custom filters and middleware:

```go
import (
    "github.com/go-kratos/kratos/v2/transport/http"
    "github.com/go-kratos/kratos/v2/middleware/tracing"
)

func main() {
    srv := http.NewServer(
        http.Address(":8080"),
        http.Middleware(tracing.Server()),
        http.Filter(func(next http.Handler) http.Handler {
            return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                // Pre-processing logic
                next.ServeHTTP(w, r)
            })
        }),
    )
    srv.Start(context.Background())
}

```

*Source: [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go) defines the filter chain composition and server initialization.*

### Creating a gRPC Server with Interceptors

The gRPC implementation uses distinct options for unary and stream interceptors:

```go
import (
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/go-kratos/kratos/v2/middleware/logging"
)

func main() {
    srv := grpc.NewServer(
        grpc.Address(":9000"),
        grpc.UnaryInterceptor(logging.UnaryServerInterceptor()),
        grpc.StreamInterceptor(logging.StreamServerInterceptor()),
        // Reflection enabled by default
    )
    srv.Start(context.Background())
}

```

*Source: [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go) handles the interceptor registration and health service setup.*

### Running Both Transports Simultaneously

Both servers implement identical lifecycle methods, enabling mixed deployments:

```go
func main() {
    httpSrv := http.NewServer(http.Address(":8080"))
    grpcSrv := grpc.NewServer(grpc.Address(":9000"))

    go httpSrv.Start(context.Background())
    go grpcSrv.Start(context.Background())
    
    // Wait for shutdown signal
}

```

## Summary

- **HTTP transport** uses [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go) with gorilla/mux routing, filter chains, and standard `net/http` semantics.
- **gRPC transport** uses [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go) with interceptors, automatic health/reflection services, and `grpc.Server` embedding.
- **Middleware patterns** differ: HTTP uses `FilterFunc` and `middleware.Matcher`, while gRPC separates unary and stream interceptors.
- **Routing** is path-based in HTTP (gorilla/mux) versus method-name-based in gRPC (protobuf services).
- **Built-in services**: gRPC provides health checks and reflection automatically; HTTP requires manual implementation.
- **TLS handling** attaches directly to HTTP servers but converts to `grpc.Credentials` for gRPC.
- **Both transports** share `transport.Server` interface compatibility, enabling unified application startup and shutdown logic.

## Frequently Asked Questions

### How does Kratos handle metadata differently between HTTP and gRPC?

HTTP transports metadata through standard HTTP headers using `headerCarrier` to wrap the `http.Header` type. In [`transport/grpc/interceptor.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/interceptor.go), gRPC metadata is handled by the internal `apimd.Server` which exposes Kratos metadata service through gRPC's metadata APIs. The HTTP implementation accesses headers directly from the request object, while gRPC extracts metadata from the call context using `metadata.FromIncomingContext`.

### Can I use the same middleware for both HTTP and gRPC servers?

Not directly, due to different function signatures. HTTP middleware uses `middleware.Middleware` that processes `context.Context` and requests through the filter chain. gRPC requires `UnaryServerInterceptor` or `StreamServerInterceptor` types from the `google.golang.org/grpc` package. While the business logic might be similar, you must create protocol-specific wrappers or use Kratos's abstraction layers to share cross-cutting concerns between transports.

### Why does the gRPC server have built-in health checks but HTTP doesn't?

The gRPC ecosystem standardized health checking via the `grpc.health.v1` protocol, which Kratos automatically registers in [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go) unless `CustomHealth` is specified. HTTP has no equivalent universal standard in the Go standard library, so Kratos leaves health endpoint implementation to application developers. You must manually register health handlers on the HTTP router using standard HTTP status codes and response formats.

### Which transport should I choose for my Kratos service?

Choose **gRPC** for internal service-to-service communication requiring high performance, strong typing via Protocol Buffers, streaming, or automatic client generation. Choose **HTTP** for external-facing APIs, browser clients, or when you need flexible routing, human-readable debugging, or RESTful semantics. Many production deployments use both simultaneously—HTTP on port 8080 for external traffic and gRPC on port 9000 for internal microservice communication.