gRPC vs REST: cuándo usar cada uno
Comparación práctica de gRPC y REST en servicios backend: rendimiento, experiencia de desarrollo, streaming y los compromisos que deciden cuál usar.

REST es el estilo de API por defecto para servicios web. gRPC es el estándar por defecto para la comunicación de alto rendimiento entre servicios. Pero la elección no siempre es obvia: muchos equipos eligen REST cuando gRPC les ahorraría dolores de cabeza reales de ingeniería, y otros adoptan gRPC cuando REST habría sido perfectamente suficiente.
La respuesta depende de quiénes son tus clientes, qué rendimiento necesitas, si necesitas streaming y cuánto valoras la compatibilidad con el navegador frente a la seguridad de tipos.
La diferencia fundamental
REST usa HTTP/1.1 (o HTTP/2), envía JSON (normalmente) y se apoya en las rutas de la URL y en los verbos HTTP para su semántica. gRPC usa HTTP/2, envía payloads binarios de Protocol Buffers y define servicios y métodos en archivos .proto que generan código tipado de cliente y de servidor.
// 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;
}Comparación de rendimiento
La serialización binaria de gRPC y el multiplexado de HTTP/2 le dan una ventaja de rendimiento significativa en la comunicación entre servicios.
// 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: donde gRPC brilla
gRPC soporta de forma nativa cuatro patrones de comunicación. REST soporta petición-respuesta. Todo lo demás requiere soluciones alternativas como WebSockets, Server-Sent Events o 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);
}Compromisos en la experiencia de desarrollo
// 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 readableMarco de decisión
// 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
};Puntos clave
- REST para APIs externas, gRPC para servicios internos — el patrón más común y práctico en las arquitecturas modernas
- La seguridad de tipos de gRPC evita el desfase de esquemas — el archivo
.protoes a la vez la documentación y la fuente de la generación de código - La serialización binaria importa a escala — los Protocol Buffers son de 3 a 10 veces más pequeños y de 2 a 5 veces más rápidos de serializar que JSON
- El streaming es la funcionalidad estrella de gRPC — el streaming de servidor, de cliente y bidireccional son ciudadanos de primera clase
- REST es más fácil de depurar y de adoptar — cURL, las DevTools del navegador y la familiaridad universal hacen que REST tenga menos fricción para la mayoría de equipos
- Considera un enfoque híbrido — una pasarela REST para los clientes externos y gRPC entre los servicios internos ofrece el mejor equilibrio


