gRPC Elixir: Stream-Based RPC Servers and Clients
An Elixir implementation of gRPC
At a glance
- What is it?
- gRPC Elixir implements gRPC for BEAM applications with unary and streaming calls, interceptors, HTTP transcoding, TLS, and a unified stream API. Its current repository is not archived and its last push was on 2026-09-08, although the installation example still references version 0.11 while recent releases use version 1.0.x.
- Who is it for?
- Adopt gRPC Elixir when an Elixir service needs protobuf-based RPC and the team wants unary and streaming calls to share one stream-based programming model. Do not adopt it without checking application startup, transport selection, generated code, and deployment requirements that are not fully covered by the README.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 45 days ago.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why gRPC Elixir Uses One Stream Model
gRPC Elixir addresses Elixir developers who need to expose or consume services through Google's gRPC protocol rather than implementing HTTP/2 and protobuf handling independently. Its documented feature set includes unary RPC, server-side streaming, bidirectional streaming, interceptors, HTTP transcoding, TLS, metadata, compression, client adapters, and server reflection through an optional package. These facilities place it between raw protobuf serialization and a complete RPC framework.
The library's central design choice is a unified stream-based model. A request or response is represented as a stream, and server handlers compose streams rather than returning a bare response struct. This matters because a service containing several call types does not need separate programming styles for each RPC mode. Even the unary handler in the README begins with `GRPC.Stream.unary/2`, then applies transformations and materializes the result with `GRPC.Stream.run/1`.
That consistency also changes how handlers are written. A server-side streaming method can wrap an Elixir stream with `GRPC.Stream.from/1`, while a bidirectional method can join incoming and outgoing streams with `join_with: output_stream`. The model suits ordinary BEAM pipelines and functions such as `map/2`, but it imposes a learning cost on developers accustomed to the deprecated direct-reply API. The README says that `GRPC.Server.send_reply/2` and direct struct returns were deprecated as of version 0.10.x, so new implementations should follow the stream API rather than mixing it with the older pattern.
From .proto Definitions to Generated Elixir Modules
gRPC Elixir does not treat an Elixir function as a complete service definition. Developers first define messages and methods in a protobuf schema, then use `protoc` with the protobuf Elixir plugin to generate the required files. In the repository layout, protocol-facing implementations are split among `grpc/`, `grpc_core/`, and `grpc_server/`, while `interop/` provides a separate area for interoperability material. This separation suggests that core protocol support and the server component are packaged independently.
The example schema contains `HelloRequest`, `HelloReply`, and a `GreetingServer` service. It declares a unary method, a method that returns a server stream, and a method whose request and response are both streams. The protobuf definitions establish field numbers and service contracts, while the generated Elixir modules provide the message structs and service behavior expected by handlers.
The documented compiler command places generated code under `./lib` and searches for imported files under `./priv/protos`:
protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.protoThis command requires the protobuf Elixir plugin to be available to `protoc`. The README also points to the `protobuf_generate` Hex package as another route for generating necessary files, but it does not provide a complete configuration snippet for that package. Generated modules must align with the `service:` value passed to `use GRPC.Server`. In the example, `use GRPC.Server, service: Helloworld.GreetingServer.Service` binds the handler module to the `GreetingServer` contract from the schema.
Adding gRPC Packages to an Elixir Application
The README gives a Mix dependency entry rather than a shell installation command. Add the server package explicitly because the note states that server use requires `:grpc_server` instead of relying on the older `:grpc` package. The `:protobuf` dependency is optional when an application imports well-known Google types, and `:grpc_reflection` is optional when server reflection is required.
The documented dependency block is:
def deps do
[
{:grpc, "~> 0.11"},
{:grpc_server, "~> 0.11"},
{:protobuf, "~> 0.14"}, # optional for import wellknown google types
{:grpc_reflection, "~> 0.2"} # optional enable grpc reflection
]
endAdd this block to the `deps` list in `mix.exs`, then run `mix deps.get` from the application directory. The repository Dockerfile shows the normal dependency setup sequence as `mix local.hex --force`, `mix local.rebar --force`, `MIX_ENV=${MIX_ENV} mix deps.get`, `MIX_ENV=${MIX_ENV} mix deps.compile`, and `MIX_ENV=${MIX_ENV} mix compile`. Those commands prepare the local Hex and Rebar tooling, fetch dependencies, compile them, and compile the application.
There is a version-documenting problem that should be resolved before adoption. The installation block requires the 0.11 series, but the recent release list contains v1.0.5, v1.0.3, and v1.0.2. The repository layout also indicates that `:grpc` and `:grpc_server` are distinct components. Readers should inspect the dependency requirements of the exact release they intend to use rather than assuming the README block is current.
Implementing a First Greeting Service
A first service needs a generated service module, a handler module, and a stream pipeline. The unary handler below receives a generated request struct and a materializer, converts the request into a unary stream, maps the reply message, and materializes the pipeline. The materializer is passed through instead of being discarded because stream execution requires it.
defmodule HelloworldStreams.Server do
use GRPC.Server, service: Helloworld.GreetingServer.Service
alias GRPC.Stream
alias Helloworld.HelloRequest
alias Helloworld.HelloReply
def say_unary_hello(request, materializer) do
request
|> GRPC.Stream.unary(materializer: materializer)
|> GRPC.Stream.map(fn %HelloReply{} = reply ->
%HelloReply{message: "[Reply] #{reply.message}"}
end)
|> GRPC.Stream.run()
end
endThe `use GRPC.Server` declaration connects the module to `Helloworld.GreetingServer.Service`. The schema's request and response types determine the generated `HelloRequest` and `HelloReply` structs.
The server need not stop at unary behavior. A server stream can produce ten replies from a request, while a bidirectional stream can combine incoming requests with an independently produced output stream. Both examples use `GRPC.Stream.run_with(materializer)`, confirming that materialization is where the declared stream operations become an executable RPC response.
Streaming, Effects, and Error Recovery Boundaries
The stream API also provides `effect/2` for side effects and `map_error/2` for recovery. According to the README, `effect/2` invokes a callback for each item but ignores its return value. This preserves the stream while allowing logging, metrics, auditing, or notifications to react to values. The callback runs lazily when `run/1`, `run_with/3`, or `to_flow/1` materializes the stream. Exceptions raised inside the callback are captured internally, so a failing logging or notification callback does not interrupt the data flow.
That exception policy is convenient for observability, but it also creates an operational boundary. Because the callback exception is captured internally, the application will not receive it as a normal stream failure. Teams using `effect/2` for required business actions should not treat those actions as guaranteed processing steps. The README positions the operator for reactions around the stream, not for changing or filtering messages.
`map_error/2` is the documented recovery point for expected `{:error, reason}` values and unexpected exceptions emitted by earlier stages. The README names this mechanism but does not show the complete operator pipeline. The documentation therefore confirms the error categories and intent, but it does not establish the exact return type expected by a server method, retry behavior, or whether one upstream exception can be recovered more than once.
Streaming also has workload implications. The server-side example uses `Stream.repeatedly/1` followed by `Stream.take(10)`, which gives each client ten generated messages in that example. Production methods must decide when streams terminate, how large messages may be, and how backpressure is handled. The README does not document those limits, so they cannot be inferred from the library's feature list.
Client Transport, TLS, and Interceptor Choices
gRPC Elixir's client side is documented as supporting basic connections and RPC calls, interceptors, target schemes, resolvers, compression, metadata, and client adapters. A client therefore has more configuration choices than a function that simply accepts a URI. Target selection can use supported formats including DNS names and Unix sockets, while the Mint adapter provides one transport implementation. TLS is listed as a supported capability, which makes transport security part of the client configuration rather than an application-level afterthought.
Interceptors appear alongside client and server capabilities in the project description. Their practical value would be cross-cutting request handling, such as adding metadata or applying consistent policy, but the README does not show an interceptor callback, ordering rule, or failure behavior. It would be incorrect to claim that every interceptor can mutate requests or responses based solely on the feature name.
The alternative to using the library directly is to build a service around an HTTP/2 client and protobuf-generated modules while handling gRPC framing, status propagation, deadlines, metadata, and stream lifecycles separately. That approach can fit an existing transport abstraction, but it requires the application to implement the protocol integration itself. gRPC Elixir removes much of that assembly and offers one abstraction across unary and streaming calls, at the cost of adopting its stream pipeline and package split. The actual adapter choice should be checked against the application's runtime and deployment environment, neither of which is specified in the repository files.
Maintenance, Packaging, and Upgrade Cost
The repository is not archived, and the last push was on 2026-09-08. Recent releases listed for the project are v1.0.5 from 2026-08-31, v1.0.3 from 2026-07-27, and v1.0.2 from 2026-06-30. Those facts indicate recent development activity, but they do not by themselves define compatibility, upgrade effort, or production suitability.
The license is Apache-2.0. That identifies the project's published license, while individual deployments still need to review how the license, generated protobuf files, dependencies, and distributed artifacts apply to their use. This review is a compliance step, not legal advice.
The repository contains separate top-level components for `grpc`, `grpc_core`, and `grpc_server`, plus interoperation and benchmark directories. An upgrade may therefore involve more than editing one dependency line. The README explicitly notes that the server moved to the `:grpc_server` dependency starting with the v1.0.0 release candidate series, which makes package boundaries relevant during migration. It also warns that the old server reply API was deprecated. Applications should inspect generated service modules and handlers for direct struct returns before changing dependency versions.
The included Dockerfile targets `elixir:1.8.1` and runs `mix deps.get`, `mix deps.compile`, and `mix compile`. That file documents a reproducible container build path, but it also means the container is based on a specific older Elixir image. The README does not state the current supported Elixir range, so compatibility with a newer application image must be verified in `mix.exs` and release documentation.
Editorial conclusion
Adopt gRPC Elixir when an Elixir service needs protobuf-based RPC and the team wants unary and streaming calls to share one stream-based programming model. Do not adopt it without checking application startup, transport selection, generated code, and deployment requirements that are not fully covered by the README. Verify the dependency versions first, because the README shows `{:grpc, "~> 0.11"}` and `{:grpc_server, "~> 0.11"}` while the release history includes v1.0.5, making the documented installation constraint an immediate compatibility question.
Frequently asked questions
How do I install gRPC Elixir?
The README shows adding `:grpc`, `:grpc_server`, and optionally `:protobuf` and `:grpc_reflection` to the `deps` list in `mix.exs`. It documents `protoc --elixir_out=plugins=grpc:./lib -I./priv/protos helloworld.proto` for the example schema.
How does gRPC Elixir implement unary RPCs?
Unary calls use the same stream-based model as other RPC types. The example converts the request with `GRPC.Stream.unary/2`, maps the reply, and calls `GRPC.Stream.run/1` with the supplied materializer.
Does gRPC Elixir support server-side and bidirectional streaming?
Yes. The README shows server-side streaming with `GRPC.Stream.from/1` and bidirectional streaming with `GRPC.Stream.from/2` and `join_with: output_stream`.
What license does gRPC Elixir use?
The repository identifies its license as Apache-2.0.
Is the gRPC Elixir server package separate?
Yes. The README states that the server requires the `:grpc_server` dependency rather than the older `:grpc` package, and the repository contains separate `grpc/` and `grpc_server/` entries.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/elixir-grpc-grpc)Was this useful?