gRPC vs REST: Wann was einsetzen
Praxisnaher Vergleich von gRPC und REST für Backend-Services: Performance, Developer Experience, Streaming und die entscheidenden Abwägungen.

REST ist der Standard-API-Stil für Webservices. gRPC ist der Standard für performante Kommunikation zwischen Services. Die Wahl ist aber nicht immer offensichtlich — viele Teams greifen zu REST, wo gRPC ihnen echten Entwicklungsaufwand ersparen würde, und andere setzen gRPC ein, wo REST vollkommen ausgereicht hätte.
Die Antwort hängt davon ab, wer deine Clients sind, welche Performance du brauchst, ob du Streaming benötigst und wie hoch du Browser-Kompatibilität gegenüber Typsicherheit gewichtest.
Der grundlegende Unterschied
REST nutzt HTTP/1.1 (oder HTTP/2), verschickt in der Regel JSON und leitet seine Semantik aus URL-Pfaden und HTTP-Verben ab. gRPC nutzt HTTP/2, verschickt binäre Protocol-Buffer-Payloads und definiert Services und Methoden in .proto-Dateien, aus denen typisierter Client- und Servercode generiert wird.
// REST: JSON over HTTP — human-readable, widely supported
// POST /api/users
// Content-Type: application/json
// { "name": "Alice", "email": "alice@example.com" }
// Response: 201 Created
// { "id": "user-123", "name": "Alice", "email": "alice@example.com" }
// gRPC: Protocol Buffers over HTTP/2 — binary, type-safe, fast
// Defined in a .proto file:// user_service.proto
syntax = "proto3";
package users;
service UserService {
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
rpc GetUser(GetUserRequest) returns (User);
rpc ListUsers(ListUsersRequest) returns (stream User); // Server streaming
rpc UpdateUsers(stream UpdateUserRequest) returns (UpdateUsersResponse); // Client streaming
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message CreateUserResponse {
string id = 1;
string name = 2;
string email = 3;
}
message User {
string id = 1;
string name = 2;
string email = 3;
int64 created_at = 4; // Unix timestamp
}
message GetUserRequest {
string id = 1;
}
message ListUsersRequest {
int32 page_size = 1;
string page_token = 2;
}
message UpdateUserRequest {
string id = 1;
string name = 2;
string email = 3;
}
message UpdateUsersResponse {
int32 updated_count = 1;
}Performance im Vergleich
Die binäre Serialisierung von gRPC und das Multiplexing von HTTP/2 verschaffen ihm bei der Kommunikation zwischen Services einen deutlichen Performance-Vorsprung.
// JSON serialization vs Protocol Buffers
// A typical user object in JSON: ~150 bytes
const jsonPayload = {
id: "user-123",
name: "Alice Johnson",
email: "alice@example.com",
createdAt: 1648684800,
roles: ["admin", "editor"],
};
// JSON.stringify: ~120 bytes
// Same data in Protocol Buffers: ~45 bytes
// Binary encoding: field numbers + wire types + values
// No field names transmitted — just indices
// 60-70% smaller on average for typical payloads
// Performance implications at scale:
// 10,000 requests/second × 150 bytes (JSON) = 1.5 MB/s network
// 10,000 requests/second × 45 bytes (Protobuf) = 0.45 MB/s network
// 3x less bandwidth, 2-5x faster serialization/deserialization// ❌ Using REST/JSON for high-throughput internal services
interface InternalServiceCall {
protocol: 'REST/JSON';
serialization: '~5ms per large payload';
networkOverhead: 'HTTP/1.1 head-of-line blocking, text headers';
typesSafety: 'Manual — OpenAPI spec may drift from implementation';
// At 50k req/s between services, this adds up significantly
}
// ✅ Using gRPC for high-throughput internal services
interface OptimizedServiceCall {
protocol: 'gRPC/Protobuf';
serialization: '~0.5ms per large payload';
networkOverhead: 'HTTP/2 multiplexing, binary headers';
typeSafety: 'Generated code — proto file IS the implementation contract';
// 10x serialization improvement, multiplexed connections
}Streaming: wo gRPC glänzt
gRPC unterstützt vier Kommunikationsmuster nativ. REST unterstützt Request-Response. Alles andere erfordert Behelfslösungen wie WebSockets, Server-Sent Events oder Long Polling.
// gRPC streaming patterns
// 1. Unary — standard request/response (like REST)
// Client sends one message, server sends one response
async function getUser(id: string): Promise<User> {
return client.getUser({ id });
}
// 2. Server streaming — server sends a stream of responses
// Client sends one request, server sends many responses
async function* listUsers(pageSize: number): AsyncGenerator<User> {
const stream = client.listUsers({ pageSize, pageToken: '' });
for await (const user of stream) {
yield user;
}
}
// 3. Client streaming — client sends a stream of requests
// Client sends many messages, server sends one response
async function batchUpdateUsers(
updates: AsyncIterable<UpdateUserRequest>
): Promise<UpdateUsersResponse> {
return client.updateUsers(updates);
}
// 4. Bidirectional streaming — both sides stream simultaneously
// Client and server send messages independently
async function syncUsers(
localChanges: AsyncIterable<UserChange>,
onRemoteChange: (change: UserChange) => void
): Promise<void> {
const stream = client.syncUsers();
// Send local changes
for await (const change of localChanges) {
stream.write(change);
}
// Receive remote changes
stream.on('data', onRemoteChange);
}Abwägungen bei der Developer Experience
// REST developer experience
// Pros:
// - cURL-friendly: curl http://localhost:3000/api/users/123
// - Browser-testable: just open the URL
// - Massive ecosystem: Express, Fastify, every HTTP library
// - Human-readable payloads: JSON is text
// - Low barrier to entry: everyone knows HTTP + JSON
// Cons:
// - No generated types: you write clients manually
// - Schema drift: OpenAPI spec and code get out of sync
// - Verbose: HTTP headers, JSON keys repeated in every message
// - No native streaming: need WebSockets or SSE for real-time
// gRPC developer experience
// Pros:
// - Generated clients: proto file → TypeScript/Go/Python/etc.
// - Type safety: compiler catches mismatches between services
// - Built-in streaming: first-class support for all 4 patterns
// - Performance: binary serialization, HTTP/2 multiplexing
// Cons:
// - Not browser-native: need gRPC-Web proxy or Connect
// - Harder to debug: binary payloads aren't human-readable
// - Tooling complexity: protoc compiler, code generation pipeline
// - Smaller ecosystem: fewer middleware options than REST// REST: easy to debug with standard tools
// $ curl -s http://localhost:3000/api/users/123 | jq
// {
// "id": "user-123",
// "name": "Alice",
// "email": "alice@example.com"
// }
// gRPC: need specialized tools
// $ grpcurl -plaintext localhost:50051 users.UserService/GetUser
// Requires grpcurl, grpc_cli, or Postman gRPC support
// Binary payload must be decoded to be readableEntscheidungsrahmen
// When to choose REST
const chooseREST = {
publicAPI: true, // Clients are external developers
browserClients: true, // Frontend applications consume the API
simpleCRUD: true, // Standard create/read/update/delete
teamFamiliarity: 'REST', // Team knows REST, not gRPC
debuggability: 'important', // Need to curl and inspect easily
ecosystem: 'broad', // Need extensive middleware options
};
// When to choose gRPC
const chooseGRPC = {
serviceToService: true, // Internal communication between services
highThroughput: true, // 10k+ requests/second between services
streaming: true, // Real-time data feeds, event streams
polyglot: true, // Services in different languages need type safety
latencySensitive: true, // Every millisecond matters
strictContracts: true, // Schema-first development with enforcement
};
// The hybrid approach: REST for external, gRPC for internal
const hybridArchitecture = {
externalAPI: 'REST/JSON', // Public-facing, browser-friendly
apiGateway: 'translates', // Converts REST ↔ gRPC at the boundary
internalServices: 'gRPC', // Type-safe, high-performance
// Best of both worlds — but adds gateway complexity
};Die wichtigsten Punkte
- REST für externe APIs, gRPC für interne Services — das gängigste und praktikabelste Muster für moderne Architekturen
- Die Typsicherheit von gRPC verhindert Schema-Drift — die
.proto-Datei ist zugleich Dokumentation und Quelle der Codegenerierung - Binäre Serialisierung macht sich bei Scale bemerkbar — Protocol Buffers sind 3- bis 10-mal kleiner und lassen sich 2- bis 5-mal schneller serialisieren als JSON
- Streaming ist das Killer-Feature von gRPC — Server-Streaming, Client-Streaming und bidirektionales Streaming sind erstklassig unterstützt
- REST ist leichter zu debuggen und einzuführen — cURL, die Browser-DevTools und die allgemeine Vertrautheit sorgen für weniger Reibung in den meisten Teams
- Zieh einen hybriden Ansatz in Betracht — ein REST-Gateway für externe Clients und gRPC zwischen den internen Services bietet die besten Kompromisse


