Serving gRPC from Play

To be able to serve gRPC from a Play Framework app you must enable HTTP/2 Support with HTTPS and the ALPN agent.


To use gRPC in Play Framework you must enable HTTP/2 Support.

Generating classes from the gRPC service definition is done by adding the Akka gRPC plugin to your sbt build along with the Play gRPC generators:

// in project/plugins.sbt:
addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "1.0.2")
resolvers += Resolver.bintrayRepo("playframework", "maven")
libraryDependencies += "" %% "play-grpc-generators" % "0.9.1"

Then you need to enable the Play server side code generator in build.sbt:

import play.grpc.gen.scaladsl.PlayScalaServerCodeGenerator
akkaGrpcExtraGenerators += PlayScalaServerCodeGenerator
libraryDependencies += "" %% "play-grpc-runtime" % "0.9.1"
import play.grpc.gen.javadsl.PlayJavaServerCodeGenerator
akkaGrpcExtraGenerators += PlayJavaServerCodeGenerator
libraryDependencies += "" %% "play-grpc-runtime" % "0.9.1"

The plugin will look for .proto service descriptors in app/protobuf and output an abstract class per service that you then implement, so for example for the following protobuf descriptor:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "example.myapp.helloworld.grpc";
option java_outer_classname = "HelloWorldProto";

package helloworld;

service GreeterService {
    rpc SayHello (HelloRequest) returns (HelloReply) {}

message HelloRequest {
    string name = 1;

message HelloReply {
    string message = 1;

You will get an abstract class named example.myapp.helloworld.grpc.helloworld.AbstractGreeterServiceRouter example.myapp.helloworld.grpc.AbstractGreeterServiceRouterCreate a concrete subclass implementing this wherever you see fit in your project, let’s say controller.GreeterServiceImpl like so:

package controllers

import example.myapp.helloworld.grpc.helloworld.AbstractGreeterServiceRouter
import example.myapp.helloworld.grpc.helloworld.HelloReply
import example.myapp.helloworld.grpc.helloworld.HelloRequest
import javax.inject.Inject
import javax.inject.Singleton

import scala.concurrent.Future

/** User implementation, with support for dependency injection etc */
class GreeterServiceImpl @Inject() (implicit actorSystem: ActorSystem)
    extends AbstractGreeterServiceRouter(actorSystem) {

  override def sayHello(in: HelloRequest): Future[HelloReply] = Future.successful(HelloReply(s"Hello, ${}!"))

package controllers;

import example.myapp.helloworld.grpc.AbstractGreeterServiceRouter;
import example.myapp.helloworld.grpc.HelloReply;
import example.myapp.helloworld.grpc.HelloRequest;

import javax.inject.Singleton;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/** User implementation, with support for dependency injection etc */
public class GreeterServiceImpl extends AbstractGreeterServiceRouter {

  public GreeterServiceImpl(Materializer mat, ActorSystem actorSystem) {
    super(mat, actorSystem);

  public CompletionStage<HelloReply> sayHello(HelloRequest in) {
    String message = String.format("Hello, %s!", in.getName());
    HelloReply reply = HelloReply.newBuilder().setMessage(message).build();
    return CompletableFuture.completedFuture(reply);

And then add the router to your Play conf/routes file. Note that the router already knows its own path since it is based on the package name and service name of the service and therefore the path / is enough to get it to end up in the right place (in this example the path will be /helloworld.GreeterService). It cannot be added at an arbitrary path (if you try to do so an exception will be thrown when the router is started).

->     /   controllers.GreeterServiceImpl

A gRPC client can now connect to the server and call the provided services.

Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.