Streaming RPCs and Backpressure
Handle server, client, and bidirectional streaming with @GrpcStreamMethod and observables.
Four gRPC Call Shapes
gRPC defines four kinds of RPC, distinguished by whether each side sends a single message or a stream:
- Unary — one request, one response. The default; modeled in NestJS with a plain method returning a value or
Observable. - Server streaming — one request, the server emits a stream of responses.
- Client streaming — the client emits a stream of requests, the server replies once.
- Bidirectional — both sides stream independently over the same HTTP/2 connection.
Streaming matters for enterprise APIs: live price feeds, log tailing, file chunk upload, and chat all map naturally onto one of the three streaming shapes instead of polling.
Declaring Streams in Protobuf
The stream keyword in your .proto service definition is what selects the call shape. Put it on the request, the response, or both.
NestJS reads this contract at startup and wires each RPC to a handler. A method whose response is stream must be implemented as an @GrpcStreamMethod (or @GrpcStreamCall), not a plain @GrpcMethod.
syntax = "proto3";
package trading;
service PriceService {
// server streaming: one subscribe, many ticks
rpc Subscribe (SubscribeRequest) returns (stream PriceTick);
// client streaming: many orders, one ack
rpc PlaceOrders (stream Order) returns (OrderAck);
// bidirectional: stream in, stream out
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}
message SubscribeRequest { string symbol = 1; }
message PriceTick { string symbol = 1; double price = 2; int64 ts = 3; }
message Order { string id = 1; int32 qty = 2; }
message OrderAck { int32 accepted = 1; }
message ChatMessage { string user = 1; string text = 2; }