La muerte de JSON en el backend: Por qué migré toda mi stack a gRPC y Protobuf
Empezaré este post con una confesión que podría ganarme algunos enemigos: Odio JSON.
No es un odio irracional, de esos que aparecen de la nada. Es un odio construido, ladrillo a ladrillo, a lo largo de años depurando payloads malformados, campos que deberían haber sido números pero llegaron como strings, y ese clásico null donde esperabas un array vacío. JSON es el equivalente digital de una conversación telefónica con tu abuela: crees que entendiste lo que dijo, pero cuando llegas, el pastel de zanahoria no tenía ese glaseado de chocolate esperado (los brasileños entenderán).

Durante años, acepté esta tortura como parte del contrato social de ser un desarrollador backend. “Es el estándar”, decían. “Todo el mundo lo usa”, repetían. Y yo, como un buen corderito, seguía serializando y deserializando texto como si estuviéramos en 2005 y el ancho de banda fuera infinito.
Hasta que ya fue suficiente.
El Problema: El Texto es Costoso
Hagamos un ejercicio mental. Imagina que necesitas enviar el número 42 desde tu backend en Go a tu app en Flutter.
En JSON, esto se convierte en:
{"answer": 42}
Eso son 14 bytes de texto. Parece muy poco, ¿verdad? Ahora imagina que estás enviando una lista de 10,000 transacciones financieras, cada una con 15 campos. De repente, ese “texto legible por humanos” se convierte en megabytes de desperdicio.
El análisis de JSON es un ritual de sacrificio de CPU. Tu servidor necesita:
- Convertir la estructura de Go a texto.
- Serializar ese texto en UTF-8.
- Enviarlo por la red.
- El cliente recibe el texto.
- El cliente analiza el texto de vuelta a una estructura.
- El cliente reza para que los tipos sean correctos.
Cada uno de estos pasos consume ciclos de procesamiento. Y como dije en mi post Sobre Mí: los bits consumen energía. Desperdiciarlos es moralmente ofensivo.
La Solución: Protobuf y la Belleza de lo Binario
Protocol Buffers (Protobuf) es el formato de serialización creado por Google para resolver exactamente este problema. En lugar de texto, defines un contrato (un archivo .proto), y el compilador genera código nativo para cualquier lenguaje.
Ese mismo {"answer": 42} en Protobuf? 2 bytes. No es magia, es matemática. Lo binario es simplemente más eficiente que el texto.
Pero el ahorro de ancho de banda es solo la guinda del pastel. El verdadero regalo es el tipado fuerte.
syntax = "proto3";
message Transaction {
string id = 1;
int64 amount_cents = 2;
string currency = 3;
int64 timestamp = 4;
TransactionType type = 5;
}
enum TransactionType {
UNKNOWN = 0;
CREDIT = 1;
DEBIT = 2;
}
Con este archivo, genero código para Go, Dart (Flutter) y TypeScript (SolidJS) con un solo comando. Si cambio el tipo de amount_cents de int64 a string, el compilador me grita antes de que despliegue. Ya no existe esa pesadilla de “funcionó en Postman pero se rompió en la app”.
gRPC: El Matrimonio Perfecto con HTTP/2
Protobuf es el formato. gRPC es el protocolo de comunicación que usa este formato. Y aquí es donde las cosas se ponen interesantes para aquellos a quienes les importa el rendimiento móvil.
gRPC funciona sobre HTTP/2 por defecto (y ya tiene soporte experimental para HTTP/3). Esto significa:
Multiplexación: Múltiples llamadas en la misma conexión TCP. Sin abrir y cerrar conexiones para cada petición.
Compresión de cabeceras: HTTP/2 usa HPACK para comprimir cabeceras repetitivas. En REST, envías
Content-Type: application/jsonen cada petición. En gRPC, esto se negocia una vez.Streaming bidireccional: ¿Quieres un chat en tiempo real? ¿WebSockets? Olvídalo. gRPC lo hace de forma nativa.
Para una app móvil en Flutter que consume datos de un backend en Go, la diferencia es brutal. Menos bytes transferidos significa menos batería consumida, tiempos de carga más cortos y menos posibilidades de que el usuario se rinda y se vaya a ver TikTok.
La Stack: Go + Flutter + SolidJS
Mi arquitectura actual funciona así:
- Backend en Go: Uso
protoc-gen-goyprotoc-gen-go-grpcpara generar los stubs. El servidor es ridículamente rápido porque Go ya es rápido, y ahora no necesita perder tiempo analizando JSON. - Móvil en Flutter: Uso el paquete
grpcde Dart. El código generado por Protobuf es type-safe. Si el backend cambia un campo, la app no compilará hasta que lo actualice. Eso es seguridad. - Web en SolidJS: Aquí viene la única pega. Los navegadores no hablan gRPC de forma nativa (todavía). La solución es usar gRPC-Web, un proxy que traduce llamadas HTTP/1.1 a gRPC. No es perfecto, pero sigue siendo mejor que REST puro.
El archivo .proto es la única fuente de verdad. Lo edito una vez, ejecuto el compilador, y todas las plataformas están sincronizadas. No más jugar a ese juego de mantener tres versiones diferentes de DTOs en tres lenguajes distintos.
El Elefante en la Habitación: Depuración
Seré honesto: depurar gRPC es más difícil que depurar REST. No puedes simplemente abrir el navegador y mirar el payload en la pestaña Network. Lo binario no es legible por humanos.
Para esto, uso grpcurl (el curl del mundo gRPC) y Kreya (una alternativa a Postman para gRPC). También configuro logging estructurado en el servidor para capturar las peticiones deserializadas.
Es un costo de configuración inicial. Pero una vez que te acostumbras, no vuelves atrás.
Cuándo NO usar gRPC
Como todo en tecnología, no todo son rosas. gRPC es excesivo para:
APIs públicas: Si estás creando una API para que terceros la consuman, JSON/REST sigue siendo el estándar. Nadie quiere aprender tu esquema Protobuf solo para integrarse. No seas molesto.
Proyectos pequeños: Si tu backend es un simple CRUD con 5 endpoints, la complejidad adicional no vale la pena.
SEO y rastreadores: Los bots de Google no entienden gRPC. Si necesitas que tu contenido sea indexado, REST + JSON es el camino.
En mi caso, estoy enfocado en sistemas internos donde controlo todos los extremos. No tengo que preocuparme por la compatibilidad externa.
Conclusión: JSON No Está Muerto, Pero Debería Estar de Licencia
Mira, JSON no va a desaparecer. Es el inglés del mundo de las APIs: no es el mejor lenguaje (necesito escribir un post sobre lo feo que creo que es el inglés), pero todos lo hablan. Para consumo humano, depuración rápida y prototipado, todavía tiene su lugar.
TODO: Escribir un post sobre lo feo que creo que es el inglés
Pero si estás construyendo sistemas de alto rendimiento, si te importa la batería del celular de tu usuario, si estás cansado de descubrir bugs de tipado en producción… quizás es hora de considerar la alternativa binaria.
Yo migré. Mi servidor me lo agradece. Mi app me lo agradece. ¿Mi cordura mental? Bueno, esa ya estaba comprometida desde el 7-1 que recibió la selección brasileña en el Mundial de 2014.
En el futuro, escribiré un post comparativo. Nada es más técnico que callarse y hacerlo, ¿verdad?
Antes de que lo olvide:
TODO: Escribir un post comparando REST x gRPC en la práctica
Eso es todo, me voy, ¡adiós!
