---
layout: default
---

# Native gRPC Compatibility

This guide explains how to make your Go Micro services compatible with native gRPC clients like `grpcurl`, `grpcui`, or clients generated by the standard `protoc` gRPC plugin in any language.

## Understanding Transport vs Server

Go Micro has two different gRPC-related concepts that are often confused:

### gRPC Transport (`go-micro.dev/v6/transport/grpc`)

The gRPC **transport** uses the gRPC protocol as a communication layer, similar to how you might use NATS, RabbitMQ, or HTTP. It does **not** guarantee compatibility with native gRPC clients.

```go
// This uses gRPC as transport but is NOT compatible with native gRPC clients
import "go-micro.dev/v6/transport/grpc"

t := grpc.NewTransport()
service := micro.NewService("helloworld",
    micro.Transport(t),
)
```

When using the gRPC transport:
- Communication between Go Micro services works fine
- Native gRPC clients (grpcurl, etc.) will fail with "Unimplemented" errors
- The protocol is used like a message bus, not as a standard gRPC server

### gRPC Server/Client (`go-micro.dev/v6/server/grpc` and `go-micro.dev/v6/client/grpc`)

The gRPC **server** and **client** provide native gRPC compatibility. These implement a proper gRPC server that any gRPC client can communicate with.

```go
// This IS compatible with native gRPC clients
import (
    "go-micro.dev/v6"
    grpcServer "go-micro.dev/v6/server/grpc"
    grpcClient "go-micro.dev/v6/client/grpc"
)

service := micro.NewService("helloworld",
    micro.Server(grpcServer.NewServer()),
    micro.Client(grpcClient.NewClient()),
)
```

## When to Use Which

| Use Case | Solution |
|----------|----------|
| Need native gRPC client compatibility | Use gRPC server/client |
| Need to call service with `grpcurl` | Use gRPC server |
| Need polyglot gRPC clients (Python, Java, etc.) | Use gRPC server |
| Only Go Micro services communicating | Either works |
| Want gRPC as a message protocol (like NATS) | Use gRPC transport |

## Complete Example: Native gRPC Compatible Service

### Proto Definition

```protobuf
syntax = "proto3";

package helloworld;
option go_package = "./proto;helloworld";

service Say {
    rpc Hello(Request) returns (Response) {}
}

message Request {
    string name = 1;
}

message Response {
    string message = 1;
}
```

### Generate Code

```bash
# Install protoc-gen-micro
go install go-micro.dev/v6/cmd/protoc-gen-micro@latest

# Generate Go code
protoc --proto_path=. \
    --go_out=. --go_opt=paths=source_relative \
    --micro_out=. --micro_opt=paths=source_relative \
    proto/helloworld.proto
```

### Server Implementation

```go
package main

import (
    "context"
    "log"

    "go-micro.dev/v6"
    grpcServer "go-micro.dev/v6/server/grpc"
    pb "example.com/helloworld/proto"
)

type Say struct{}

func (s *Say) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
    rsp.Message = "Hello " + req.Name
    return nil
}

func main() {
    // Create service with gRPC server for native gRPC compatibility
    // Note: Server must be set before Name to ensure the name is applied to the gRPC server
    service := micro.NewService("helloworld",
        micro.Server(grpcServer.NewServer()),
        micro.Address(":8080"),
    )

    service.Init()

    // Register handler
    pb.RegisterSayHandler(service.Server(), &Say{})

    // Run service
    if err := service.Run(); err != nil {
        log.Fatal(err)
    }
}
```

### Client Implementation (Go Micro)

```go
package main

import (
    "context"
    "fmt"
    "log"

    "go-micro.dev/v6"
    grpcClient "go-micro.dev/v6/client/grpc"
    pb "example.com/helloworld/proto"
)

func main() {
    // Create service with gRPC client
    service := micro.NewService("helloworld.client",
        micro.Client(grpcClient.NewClient()),
    )
    service.Init()

    // Create client - use the service name "helloworld" (not the proto package name)
    // Go Micro uses this name for registry lookup, which may differ from the package name
    sayService := pb.NewSayService("helloworld", service.Client())

    // Call service
    rsp, err := sayService.Hello(context.Background(), &pb.Request{Name: "Alice"})
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(rsp.Message) // Output: Hello Alice
}
```

### Testing with grpcurl

Once your service is running with the gRPC server, you can use `grpcurl`:

```bash
# List available services
grpcurl -plaintext localhost:8080 list

# Call the Hello method
grpcurl -proto ./proto/helloworld.proto \
    -plaintext \
    -d '{"name":"Alice"}' \
    localhost:8080 helloworld.Say.Hello
```

## Using Both gRPC Server and Client Together

For full native gRPC compatibility (both inbound and outbound), use both:

```go
package main

import (
    "go-micro.dev/v6"
    grpcClient "go-micro.dev/v6/client/grpc"
    grpcServer "go-micro.dev/v6/server/grpc"
)

func main() {
    service := micro.NewService("helloworld",
        micro.Server(grpcServer.NewServer()),
        micro.Client(grpcClient.NewClient()),
        micro.Address(":8080"),
    )

    service.Init()
    // ... register handlers
    service.Run()
}
```

## Common Errors

### "unknown service" Error with grpcurl

If you see this error:

```
ERROR:
  Code: Unimplemented
  Message: unknown service helloworld.Say
```

**Cause**: You're using the gRPC transport instead of the gRPC server.

**Solution**: Change from:

```go
// Wrong - uses transport
t := grpc.NewTransport()
service := micro.NewService("helloworld",
    micro.Transport(t),
)
```

To:

```go
// Correct - uses server
import grpcServer "go-micro.dev/v6/server/grpc"

service := micro.NewService("helloworld",
    micro.Server(grpcServer.NewServer()),
)
```

### Import Path Confusion

Note the different import paths:

```go
// Transport (NOT native gRPC compatible)
import "go-micro.dev/v6/transport/grpc"

// Server (native gRPC compatible)
import "go-micro.dev/v6/server/grpc"

// Client (native gRPC compatible)
import "go-micro.dev/v6/client/grpc"
```

### Service Name vs Package Name

When creating a client to call another service, use the **service name** passed to `micro.NewService`, not the proto package name:

```go
// If the server was started with micro.NewService("helloworld", ...)
sayService := pb.NewSayService("helloworld", service.Client())  // Use service name

// NOT the package name from the proto file
// sayService := pb.NewSayService("helloworld.Say", service.Client())  // Wrong!
```

Go Micro uses the service name for registry lookup, which may differ from the proto package name.

## Environment Variable Configuration

You can also configure the server and client via environment variables:

```bash
# Use gRPC server
MICRO_SERVER=grpc go run main.go

# Use gRPC client
MICRO_CLIENT=grpc go run main.go
```

## Summary

| Component | Import Path | Native gRPC Compatible |
|-----------|-------------|----------------------|
| Transport | `go-micro.dev/v6/transport/grpc` | ❌ No |
| Server | `go-micro.dev/v6/server/grpc` | ✅ Yes |
| Client | `go-micro.dev/v6/client/grpc` | ✅ Yes |

For native gRPC compatibility with tools like `grpcurl` or polyglot clients, always use the gRPC **server** and **client** packages, not the transport.

## Related Documentation

- [Transport](../transport.md) - Understanding transports in Go Micro
- [Plugins](../plugins.md) - Available plugins including gRPC
- [Migration from gRPC](migration/from-grpc.md) - Migrating existing gRPC services
