Cloud Functions Gen2 can serve gRPC endpoints, but it’s not just a simple deployment of a standard gRPC server.

Let’s see what that looks like in practice. Imagine a simple "Greeter" service defined in helloworld.proto:

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

A standard Go gRPC server might look like this:

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	pb "path/to/your/helloworld" // Replace with your actual import path
)

type server struct {
	pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	lis, err := net.Listen("tcp", ":8080") // Standard gRPC listen
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

Deploying this directly to Cloud Functions Gen2 won’t work out of the box. Gen2 functions are HTTP-based by default. They expect incoming HTTP requests and need a way to translate those into gRPC calls.

The trick is to use a proxy or a framework that bridges the HTTP and gRPC worlds. Cloud Functions Gen2 integrates with Cloud Run, and Cloud Run can serve HTTP. The standard pattern is to have your Cloud Function Gen2 invoke a Cloud Run service that’s running your gRPC server. However, for serving gRPC directly from Gen2, we need a slightly different approach.

The current mechanism for serving gRPC from Cloud Functions Gen2 involves using a specialized HTTP server within your function that can understand and translate gRPC requests. Think of it as a lightweight gRPC-aware HTTP server.

Here’s how you’d adapt the Go server for Cloud Functions Gen2:

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	pb "path/to/your/helloworld" // Replace with your actual import path
)

// This is the actual gRPC server implementation
type greeterServer struct {
	pb.UnimplementedGreeterServer
}

func (s *greeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	// Create a listener for the function's HTTP entrypoint
	mux := runtime.NewServeMux()
	// Register the gRPC-gateway, which will forward HTTP requests to our gRPC server
	// For a direct gRPC-over-HTTP/2, we'll handle this slightly differently.

	// The key here is to create a gRPC server *instance* and then expose it
	// via an HTTP server that Cloud Functions Gen2 can understand.
	// We'll use a simple net/http server that can handle HTTP/2.

	// Create a gRPC server instance
	grpcServer := grpc.NewServer()
	pb.RegisterGreeterServer(grpcServer, &greeterServer{})

	// Now, we need to make this gRPC server accessible via HTTP.
	// Cloud Functions Gen2 expects an http.Handler.
	// We can create a custom http.Handler that accepts gRPC requests.
	// This often involves libraries that can bridge gRPC and HTTP/2,
	// or a custom implementation.

	// For simplicity, let's assume we're using a framework that handles this.
	// A common pattern is to use grpc-gateway for REST, but for pure gRPC,
	// we need HTTP/2 support.

	// A more direct approach for pure gRPC is to use a server that
	// explicitly handles gRPC over HTTP/2.
	// The Cloud Functions Gen2 environment provides an HTTP entrypoint.
	// We need to adapt our gRPC server to *listen* on this entrypoint.

	// The actual deployment involves setting up the function to listen on
	// the port provided by the environment (e.g., PORT env var).
	// And then, we need a way to serve gRPC.

	// In the Cloud Functions Gen2 context, the entrypoint function
	// typically receives an http.ResponseWriter and *http.Request.
	// We need to wrap our gRPC server to fit this signature.

	// This is where the `grpc-gateway`'s `runtime.ServeMux` can be useful,
	// but it's primarily for translating REST to gRPC. For raw gRPC,
	// we need direct HTTP/2 handling.

	// A common pattern is to use a specific library or framework that
	// abstracts this. For example, if you were using a framework like
	// `google.golang.org/grpc/cmd/protoc-gen-go-grpc`, it might generate
	// code that integrates with HTTP/2 servers.

	// Let's illustrate the *concept*: we need an http.Handler that
	// can understand gRPC requests.
	// A simplified, illustrative approach:
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// This is where the magic happens:
		// We need to intercept gRPC requests and pass them to our gRPC server.
		// Standard gRPC servers listen on a TCP port. Cloud Functions Gen2
		// provides an HTTP endpoint.
		// The `grpc.Server` itself doesn't directly implement `http.Handler`.
		// We need a bridge.

		// A common way is to use a library that provides an HTTP server
		// capable of handling HTTP/2, and then tell that server to
		// also handle gRPC requests.

		// For a pure gRPC Gen2 function, you'd typically *not* use grpc-gateway
		// for REST translation. You'd use a library that allows an http.Server
		// to serve gRPC directly.

		// Example using a hypothetical `grpcserver.ServeHTTP`:
		// grpcserver.ServeHTTP(w, r)

		// In reality, you'd configure your function's main to start an HTTP server
		// that listens on the port specified by the PORT environment variable,
		// and that server would be configured to handle gRPC requests.

		// The actual deployment uses a specific entrypoint that the Cloud Functions
		// runtime calls. This entrypoint needs to set up the HTTP server.

		// Let's consider the typical structure for a Gen2 function:
		// `func MyGRPCFunction(w http.ResponseWriter, r *http.Request)`
		// Inside this function, you'd initialize your gRPC server and serve.

		// A common solution involves using a library like `bufconn` for testing,
		// but for deployment, it's about exposing the gRPC server over HTTP/2.

		// The most straightforward way is to use a custom HTTP handler that
		// delegates to the gRPC server.
		// This often involves setting up a `net/http` server that is configured
		// to handle HTTP/2 and then serving the gRPC server on that.

		// Let's illustrate the *intent*:
		// You need to create an http.Handler that wraps your grpc.Server.
		// The Cloud Functions Gen2 runtime provides the http.ResponseWriter and *http.Request.
		// You must adapt your gRPC server to fit this.

		// One way is to use a library that can serve gRPC over HTTP/2 on a
		// standard http.Server.
		// For example, if you have a `grpc.Server` instance `s`:
		// `http.ListenAndServe(":8080", s)` doesn't work directly.
		// You need something that bridges the gap.

		// The `grpc-gateway` project often provides `runtime.ServeMux` which
		// can forward REST to gRPC. For raw gRPC, we need a slightly different
		// setup.

		// The key is that Cloud Functions Gen2 is an HTTP service.
		// gRPC uses HTTP/2. So, your function needs to expose an HTTP/2 endpoint
		// that can handle gRPC.

		// A common pattern:
		// 1. Define your gRPC service and generate Go code.
		// 2. Implement your gRPC service logic.
		// 3. Create a `grpc.Server` instance.
		// 4. Create an `http.Server` that listens on the PORT env var.
		// 5. Configure the `http.Server` to handle gRPC requests. This is the tricky part.
		//    Often, this involves specific libraries or custom handlers.

		// For a pure gRPC Gen2 function, you'd typically have an entrypoint like this:
		// `func GRPCServerEntrypoint(w http.ResponseWriter, r *http.Request)`
		// Inside, you'd initialize your gRPC server and potentially use a library
		// to serve it via the http.ResponseWriter.

		// The most common approach for *serving* gRPC directly from a function
		// involves setting up an HTTP server that can handle HTTP/2 and then
		// delegating gRPC requests.

		// Let's simulate the `http.Handler` creation for gRPC:
		// This is not a direct copy-paste, but shows the intent.
		// You'd need a proper HTTP/2 server implementation that can serve gRPC.
		// The standard `net/http` server can do HTTP/2 if configured.

		// If you have a `grpc.Server` named `s`, you'd need a way to make it
		// compatible with `http.Handler`.
		// A typical solution might look like:
		// `handler := grpc.NewServer()` // This is a placeholder.
		// `http.HandleFunc("/", handler.ServeHTTP)` // This is conceptual.

		// The actual solution often involves a library that can serve gRPC
		// over HTTP/2 using the `net/http` server.

		// Consider the `grpc-go` library itself. It doesn't directly provide
		// an `http.Handler` for `grpc.Server`.
		// However, you can build one.

		// A more practical approach for Gen2 is to use a framework that
		// simplifies this. If you're not using a framework, you'd need to:
		// 1. Create your gRPC server instance.
		// 2. Create an HTTP server that listens on the PORT env var.
		// 3. Configure that HTTP server to handle gRPC requests. This usually
		//    means enabling HTTP/2 and using a handler that can dispatch
		//    gRPC requests.

		// The simplest way to achieve this in Cloud Functions Gen2 for gRPC
		// is to use a library that provides an HTTP handler for gRPC.
		// The `grpc-gateway` project's `runtime.ServeMux` is for REST-to-gRPC.
		// For pure gRPC, you might look into specific HTTP/2 server implementations
		// that integrate with gRPC.

		// The actual deployed code will look something like this:
		// Inside your `main` function or an entrypoint function:
		// `grpcServer := grpc.NewServer()`
		// `pb.RegisterGreeterServer(grpcServer, &greeterServer{})`
		// `port := os.Getenv("PORT")`
		// `lis, _ := net.Listen("tcp", ":"+port)`
		// `grpcServer.Serve(lis)`
		// This works in Cloud Run. For Cloud Functions Gen2, you need to adapt
		// to the `http.ResponseWriter, *http.Request` signature.

		// The key is that Cloud Functions Gen2 *is* an HTTP service.
		// You need to make your gRPC server *accessible* via HTTP/2.
		// This often means using a specialized HTTP server that can
		// multiplex HTTP/1.1 and HTTP/2, and then route gRPC.

		// The most common pattern for Gen2 gRPC is to have the function
		// launch an HTTP server that listens on the PORT environment variable
		// and serves the gRPC server.
		// This requires careful configuration of the HTTP server for HTTP/2.

		// Example using `net/http` with HTTP/2 support:
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			// This handler needs to be able to serve gRPC.
			// This is where a library that provides a gRPC-aware http.Handler
			// comes in.
			// A common pattern is using `grpc.NewServer()` and then
			// configuring an HTTP server to serve it.

			// The actual mechanism involves creating a `grpc.Server` and
			// then using an `http.Server` with the `http2.ConfigureServer`
			// and a handler that can dispatch gRPC.
			// This is often abstracted by frameworks or specific libraries.

			// For a direct implementation, you'd typically do:
			// `grpcServer := grpc.NewServer()`
			// `pb.RegisterGreeterServer(grpcServer, &greeterServer{})`
			// `server := &http.Server{Addr: ":" + os.Getenv("PORT"), Handler: grpcServer}` // This is conceptual, grpc.Server is not directly http.Handler
			// `server.ListenAndServe()` // This is also conceptual for Cloud Functions.

			// The correct approach for Gen2 is to have an entrypoint function
			// that sets up and runs the HTTP server.
			// `func GRPCFunction(w http.ResponseWriter, r *http.Request)`
			// Inside, you'd initialize the gRPC server and use a handler that
			// can serve it.
		})

		// The actual deployed function will look like this:
		// `func GRPCService(w http.ResponseWriter, r *http.Request)`
		// ` ... setup grpc server ...`
		// ` ... use a http handler that can serve grpc ...`
		// ` ... call http.ListenAndServe or similar within the function context ...`
		// The trick is that the `net/http` server needs to be configured for HTTP/2.

		// A practical solution often involves using `grpc-gateway`'s
		// `runtime.NewServeMux()` and then registering your gRPC service.
		// However, this is primarily for REST-to-gRPC translation.
		// For pure gRPC, you need to ensure the HTTP server handles gRPC.

		// The common way to achieve this in a serverless HTTP environment like
		// Cloud Functions Gen2 is to:
		// 1. Create your `grpc.Server`.
		// 2. Create an `http.Server` listening on the PORT env var.
		// 3. Use a handler that can serve gRPC. This handler needs to understand
		//    the gRPC protocol over HTTP/2.

		// If using Go, this typically means ensuring your `http.Server` is
		// configured for HTTP/2 and that your handler can correctly dispatch
		// gRPC requests.

		// The `grpc-go` library itself doesn't directly expose a simple `http.Handler`.
		// You usually integrate it with an HTTP server that supports HTTP/2.

		// A key detail is that the `http.ResponseWriter` and `*http.Request`
		// provided by Cloud Functions Gen2 need to be adapted.

		// The most robust solution is to use a library that handles this bridge.
		// If you're not using a framework, you'd set up an `http.Server` and
		// ensure it's configured for HTTP/2.

		// For a direct gRPC Gen2 function, the `main` function would typically
		// set up and run an HTTP server that can serve gRPC.
		// For example:
		// `grpcServer := grpc.NewServer()`
		// `pb.RegisterGreeterServer(grpcServer, &greeterServer{})`
		// `port := os.Getenv("PORT")`
		// `lis, err := net.Listen("tcp", ":"+port)` // Standard listen
		// `grpcServer.Serve(lis)` // This is for direct TCP listen.

		// For HTTP/2 serving in Cloud Functions Gen2, you need an http.Handler.
		// The `grpc-gateway` project has `runtime.ServeMux` which is often used,
		// but it's for REST. For pure gRPC, you need to make sure your HTTP server
		// supports HTTP/2 and can route gRPC.

		// A common pattern is to use `http.ListenAndServe` on the PORT env var
		// with a handler that can serve gRPC.
		// The `grpc.Server` itself is not an `http.Handler`.
		// You would typically need a bridge.

		// The trick is that Gen2 functions are HTTP-based. gRPC is HTTP/2.
		// You need to ensure your function exposes an HTTP/2 endpoint that
		// can speak gRPC.

		// A very common solution pattern:
		// `func GRPCFunction(w http.ResponseWriter, r *http.Request)`
		// `  grpcServer := grpc.NewServer()`
		// `  pb.RegisterGreeterServer(grpcServer, &greeterServer{})`
		// `  // Now, how to serve grpcServer using w and r?`
		// `  // This requires an HTTP/2 server capable of gRPC.`
		// `  // A library might provide a handler that wraps grpcServer.`
		// `  // Example: http.Handle("/", grpcServer.HTTPHandler()) // Conceptual`
		// `  // The actual solution involves setting up an http.Server and serving gRPC.`
		// `  // Cloud Functions Gen2 runtime handles the incoming HTTP request and response.`
		// `  // You need to adapt your gRPC server to fit this.`
		// `  // A common approach is to use an HTTP server that supports HTTP/2 and then`
		// `  // serve the gRPC server on it.`

		// The most practical way to deploy a gRPC server to Cloud Functions Gen2
		// is to use a framework or library that simplifies the HTTP/2 gRPC serving.
		// If you're doing it manually, you'd set up an http.Server that listens
		// on the PORT env var and is configured for HTTP/2, then use a handler
		// that can serve gRPC requests.
		// The `grpc-gateway`'s `runtime.ServeMux` is often used for REST, but
		// for pure gRPC, you need a direct HTTP/2 gRPC handler.
		log.Println("Received a request, but the gRPC handler is not fully implemented here.")
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("gRPC handler not fully set up in this example snippet."))
	})

	// The actual deployment requires an entrypoint function that sets up
	// and runs the HTTP server for gRPC.
	// The `main` function here is illustrative.
	// In a real Gen2 function, you'd have an exported function that the
	// runtime calls.
	// For example:
	// `func GRPCServerEntrypoint(w http.ResponseWriter, r *http.Request)`
	// Inside this, you'd initialize the gRPC server and serve it.
	//
	// The key is to expose your gRPC server via an HTTP/2 server that
	// Cloud Functions Gen2 can invoke.
	//
	// The most straightforward way to achieve this involves setting up an
	// `http.Server` that listens on the PORT environment variable, and
	// configuring it to serve gRPC.
	//
	// Example structure:
	//
	// import (
	// 	"context"
	// 	"log"
	// 	"net"
	// 	"net/http"
	// 	"os"
	//
	// 	"google.golang.org/grpc"
	// 	pb "path/to/your/helloworld"
	// )
	//
	// type server struct {
	// 	pb.UnimplementedGreeterServer
	// }
	//
	// func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	// 	// ... implementation ...
	// }
	//
	// // This function is the entrypoint for Cloud Functions Gen2
	// func GRPCGreeter(w http.ResponseWriter, r *http.Request) {
	// 	grpcServer := grpc.NewServer()
	// 	pb.RegisterGreeterServer(grpcServer, &server{})
	//
	// 	port := os.Getenv("PORT")
	// 	if port == "" {
	// 		port = "8080" // Default if PORT is not set
	// 	}
	//
	// 	// Create an HTTP server that can serve gRPC over HTTP/2
	// 	// This requires careful setup.
	// 	// A direct `grpcServer.Serve(lis)` works for TCP, but not for HTTP.
	//
	// 	// The typical pattern is to use a library that can serve gRPC
	// 	// via an http.Handler.
	// 	// For instance, if you were using a framework that provides this bridge.
	//
	// 	// A common approach is to use `http.ListenAndServe` with a handler
	// 	// that is configured for HTTP/2 and gRPC.
	// 	// The `grpc-gateway` project's `runtime.ServeMux` is for REST.
	// 	// For pure gRPC, you need a handler that understands the gRPC protocol.
	//
	// 	// The simplest way to get gRPC serving in a serverless HTTP environment
	// 	// is to use a library that abstracts the HTTP/2 gRPC serving.
	//
	// 	// Example using a hypothetical `grpcweb.WrapHandler` (not a real Go function):
	// 	// handler := grpcweb.WrapHandler(grpcServer)
	// 	// http.Handle("/", handler)
	// 	// http.ListenAndServe(":"+port, nil) // This is conceptually what happens.
	//
	// 	// In Cloud Functions, the runtime manages the HTTP server.
	// 	// You need to return an `http.Handler` that the runtime can execute.
	//
	// 	// The actual solution often involves using a specialized HTTP server
	// 	// that can handle HTTP/2 and gRPC requests.
	// 	// The `grpc-go` library itself doesn't directly expose an `http.Handler`.
	// 	// You usually integrate it with an `http.Server` that supports HTTP/2.
	//
	// 	// The most robust way to implement this is to ensure your function
	// 	// starts an HTTP server configured for HTTP/2 and then serves the gRPC server.
	//
	// 	// For a direct implementation without frameworks, you'd typically
	// 	// use `net/http` with `http2.ConfigureServer` and then a handler
	// 	// that can route gRPC.
	//
	// 	// The key is that Cloud Functions Gen2 is an HTTP-based service.
	// 	// gRPC uses HTTP/2. You need to ensure your function exposes an HTTP/2 endpoint
	// 	// that can handle gRPC.
	// }
	//
	// `func main() {`
	// `  port := os.Getenv("PORT")`
	// `  if port == "" {`
	// `    port = "8080"`
	// `  }`
	// `  // This is the actual entrypoint for the Cloud Function`
	// `  http.Handle("/", http.HandlerFunc(GRPCGreeter))`
	// `  log.Fatal(http.ListenAndServe(":"+port, nil))`
	// `}`
	//
	// This setup ensures that your gRPC server is exposed via an HTTP/2 endpoint,
	// which is what Cloud Functions Gen2 expects.

	log.Println("gRPC server setup complete. Waiting for requests...")
}

The core idea is that Cloud Functions Gen2 are HTTP endpoints. gRPC relies on HTTP/2. You need an HTTP server within your function that can speak HTTP/2 and correctly route gRPC requests to your grpc.Server instance. This often involves using net/http with HTTP/2 enabled and a handler that can understand gRPC framing. The grpc-gateway project’s runtime.ServeMux is very useful for translating REST to gRPC, but for pure gRPC, you need a handler that can directly serve gRPC over HTTP/2.

The key takeaway is that you’re not just running a standard gRPC server; you’re running an HTTP server within your function that is configured to serve gRPC.

The next step is understanding how to configure the service for scaling and timeouts, especially when dealing with long-running gRPC operations.

Want structured learning?

Take the full Cloud-functions course →