REST y GraphQL son dos maneras distintas de pedir datos a una API (interfaz de programación de aplicaciones), no una versión mejorada de la otra. En REST, cada recurso vive en su propia URL y el servidor fija la forma de la respuesta; en GraphQL hay un único endpoint y el cliente declara, en una consulta, los campos exactos que necesita. Esa diferencia cambia cuatro cosas de fondo: cuánto de más o de menos trae cada pedido (sobre-obtención y sub-obtención), si aparece el problema N+1 (múltiples consultas encadenadas a la base de datos), si el caché HTTP funciona gratis o hay que resolverlo a mano, y cómo se versiona la API con el tiempo. Ya vimos cómo crear y consumir una API REST; acá el foco es la comparación. Ninguno gana siempre: una consulta GraphQL mal diseñada puede costarle al servidor más que varias llamadas REST simples y bien cacheadas.
Ver índice de contenidos
Diferencia de fondo
La guía Cómo crear y consumir una API REST ya explica ese estilo a fondo: cada recurso (un usuario, un post, un comentario) tiene su propia URL y se manipula con verbos HTTP como GET, POST, PUT o DELETE. Esta guía parte de esa base y no la repite: el eje acá es la comparación con GraphQL.
GraphQL es un lenguaje de consulta para APIs, junto con un runtime del lado del servidor que ejecuta esas consultas contra los datos existentes. Lo creó Facebook en 2012, lo liberó públicamente en 2015 y hoy lo mantiene la GraphQL Foundation, bajo la Linux Foundation, con una especificación pública que se actualiza de forma periódica. A diferencia de REST, GraphQL expone un único endpoint (típicamente /graphql) contra un esquema (schema): una descripción tipada de qué datos existen y cómo se relacionan entre sí, sobre la que el cliente escribe su consulta.
No es una jerarquía de mejor a peor: son dos estilos con objetivos distintos, y presentar a GraphQL como «el reemplazo moderno de REST» es uno de los errores más repetidos sobre el tema. REST reparte los datos en recursos direccionables, cada uno con su URL, su método y su caché. GraphQL centraliza el acceso en un esquema consultable. Muchas organizaciones, de hecho, usan los dos al mismo tiempo, cada uno donde rinde mejor: incluso si la API ya está construida en Node.js y Express o en Java con Spring Boot, sumar una capa GraphQL delante suele ser más simple que reescribir todo desde cero.
Los cuatro ejes de la comparación
Más allá de la sintaxis, hay cuatro diferencias técnicas concretas que determinan cuándo conviene cada estilo. Las cuatro comparten el mismo patrón: lo que gana uno, lo paga el otro.
Sobre-obtención y sub-obtención
En REST, un endpoint fijo devuelve una forma de datos predefinida. Armar la pantalla de un perfil con sus posts requiere, de forma típica, varias llamadas, y cada una puede traer de más (sobre-obtención, over-fetching en inglés) o dejar afuera algo que hay que buscar con otra llamada (sub-obtención, under-fetching):
GET /api/usuarios/42
GET /api/usuarios/42/posts
GET /api/posts/7/comentarios
La primera llamada trae el objeto completo del usuario —nombre, email, teléfono, dirección, empresa— aunque la pantalla solo necesite el nombre. La segunda trae el cuerpo entero de cada post aunque solo haga falta el título. Y como los comentarios viven en otro recurso, hace falta una tercera llamada para completar la vista: sub-obtención.
En GraphQL, el cliente declara los campos exactos en una sola consulta, en un único viaje de ida y vuelta:
query PerfilConPosts {
usuario(id: 42) {
nombre
posts {
titulo
}
}
}
La respuesta trae nombre y el título de cada post, nada más. Es un error afirmar que REST no puede evitar la sobre-obtención: se mitiga con campos parciales (por ejemplo, ?campos=nombre,email en la query string) o con endpoints más específicos por vista, aunque diseñar y mantener esas variantes es trabajo extra del lado del servidor que GraphQL resuelve por diseño, a costa de mover esa complejidad al esquema y a los resolvers (las funciones que resuelven cada campo).
El problema N+1 y DataLoader
El segundo eje es el rendimiento en consultas anidadas. El problema N+1 aparece cuando resolver una lista de N elementos dispara una consulta adicional a la base de datos por cada uno, en lugar de traer todo junto: si una consulta devuelve 20 posts y el servidor busca el autor de cada post por separado, son 20 consultas más la que trajo los posts, 21 en total.
No es exclusivo de GraphQL —cualquier código que recorra una lista disparando una consulta por elemento puede caer en lo mismo, también en REST—, pero en GraphQL es especialmente frecuente porque el cliente puede anidar relaciones a cualquier profundidad en una sola consulta, y cada nivel puede multiplicar las consultas del nivel anterior. Decir que GraphQL no tiene problemas de rendimiento es otro error habitual: sin cuidado, una consulta anidada de tres niveles puede terminar en cientos de golpes a la base.
La solución estándar, que documenta la propia GraphQL Foundation, es DataLoader: agrupa (batching) las claves pedidas durante el mismo ciclo de la petición en una sola llamada, y además deduplica, de modo que si tres posts piden el mismo autor, se busca una única vez:
// DataLoader agrupa las claves pedidas en el mismo ciclo de la petición
// y deduplica: aunque tres posts pidan el mismo autor, se resuelve una vez.
const autorLoader = new DataLoader(async (idsAutores) => {
const autores = await db.autores.buscarPorIds(idsAutores);
return idsAutores.map((id) => autores.find((a) => a.id === id));
});
// En el resolver de cada post, en vez de una consulta por post:
const resolvers = {
Post: {
autor: (post) => autorLoader.load(post.autorId),
},
};
Sin DataLoader u otra estrategia de agrupación equivalente, una API con datos anidados y tráfico real puede volverse más lenta que la misma funcionalidad resuelta con un puñado de llamadas REST bien escritas.
Caché HTTP
El tercer eje es la caché, y ahí REST tiene una ventaja estructural. Cada recurso vive en su propia URL, y el método GET está definido como cacheable por el RFC 9110 (HTTP Semantics, del IETF): navegadores, proxies y redes de distribución de contenido (CDN) pueden guardar esa respuesta exacta y reutilizarla sin volver a golpear el servidor, con cabeceras estándar como Cache-Control o ETag.
GraphQL, en cambio, suele exponer un único endpoint y enviar todas las consultas —incluidas las de solo lectura— por POST, un método que el protocolo no trata como cacheable por defecto. Como distintas consultas llegan al mismo endpoint con cuerpos distintos, no hay una URL fija que un caché HTTP pueda usar como clave: esto rompe el caché HTTP tradicional. graphql.org documenta paliativos: exponer identificadores globales por objeto para que el propio cliente arme una caché en memoria (lo que hacen bibliotecas como Apollo Client o Relay), o servir consultas persistidas —versiones ya registradas de una consulta, identificadas por un hash corto— por GET, recuperando la cacheabilidad a costa de un paso extra de configuración que REST no necesita.
Versionado y evolución del esquema
El cuarto eje es cómo cambia la API con el tiempo. REST suele versionar la API completa: /v1/usuarios, /v2/usuarios, publicando una nueva versión cuando los cambios rompen a los clientes existentes.
GraphQL, según sus propias buenas prácticas, evita ese versionado global. Como el cliente solo recibe los campos que pidió, agregar un campo o un tipo nuevo al esquema no rompe a nadie que no lo esté pidiendo. Los campos que quedan obsoletos se marcan con la directiva @deprecated en lugar de borrarlos de golpe, y siguen funcionando mientras los clientes migran a su propio ritmo. Eso cubre el caso más común —agregar sin romper—, pero no es absoluto: cambiar el tipo o el significado de un campo existente sigue siendo un cambio disruptivo, igual que en REST.
En REST, cada endpoint suele tener su propia capa de autorización: es simple exigir que solo un administrador use DELETE /api/usuarios/42, porque ese endpoint hace una sola cosa. En GraphQL, una misma consulta puede combinar campos públicos y privados de la misma entidad, así que la autorización no se resuelve a nivel de un endpoint único: hay que aplicarla dentro de cada resolver, campo por campo. La guía de seguridad de APIs REST: autenticación, permisos y validaciones desarrolla estos patrones en detalle, y la mayoría aplica, con ajustes, a los dos estilos.
Comparación directa
Con los cuatro ejes ya vistos, conviene mirarlos juntos, más dos aspectos prácticos que también pesan en la decisión.
| Aspecto | REST | GraphQL |
|---|---|---|
| Forma de la respuesta | Fija, la define el endpoint | La define el cliente en cada consulta |
| Sobre/sub-obtención | Frecuente; se mitiga con campos parciales | Resuelta por diseño |
| Problema N+1 | Posible con ORMs mal usados | Frecuente sin DataLoader u otro batching |
| Caché HTTP | Nativa, por URL y método GET (RFC 9110) | Requiere capa adicional (IDs globales, consultas persistidas) |
| Versionado | API completa (/v1, /v2) | Esquema evolutivo con @deprecated |
| Autorización | Por endpoint y verbo | Por campo, dentro de los resolvers |
| Curva de aprendizaje | Baja, muy extendido | Media o alta: esquema, resolvers, N+1 |
Cómo elegir sin seguir la moda
No hay un ganador: hay un encaje entre lo que necesita el cliente y lo que puede sostener el servidor.
Conviene inclinarse por REST cuando los clientes son razonablemente simples y consumen formas de datos bastante fijas; cuando el caché HTTP importa de verdad —contenido público, mucho tráfico de lectura, una CDN delante—; cuando el equipo ya lo domina y no hay una presión real de sobre-obtención o sub-obtención; o cuando la superficie de la API es chica y no justifica el esquema adicional de GraphQL.
Conviene inclinarse por GraphQL cuando hay clientes muy distintos entre sí (una app móvil, un sitio web, un panel interno) que necesitan formas de datos distintas de los mismos recursos; cuando una pantalla combina datos de varias entidades relacionadas y minimizar el número de viajes de ida y vuelta importa, por ejemplo con redes de latencia alta —algo frecuente también cuando se agrega una capa GraphQL delante de varios servicios en una arquitectura de microservicios—; o cuando el equipo puede invertir en resolver bien el N+1 con DataLoader y la caché con identificadores globales o consultas persistidas.
Una consulta muy anidada, sin batching, pidiendo relaciones profundas, puede costarle al servidor mucho más que varias llamadas REST simples que una CDN cachea sin esfuerzo. La ganancia de GraphQL no es automática: depende de cómo se implementen los resolvers y de si alguien resolvió el N+1 y la caché. Por eso muchos equipos combinan los dos estilos: REST para lo público y cacheable, GraphQL para paneles internos con clientes variados.
Errores frecuentes
- Presentar a GraphQL como el reemplazo moderno de REST. Son estilos con objetivos distintos, no una evolución lineal; muchos sistemas usan los dos.
- Decir que GraphQL no tiene problemas de rendimiento. El problema N+1 es real y frecuente sin DataLoader u otra estrategia de batching.
- Afirmar que REST no puede evitar la sobre-obtención. Se mitiga con campos parciales o con endpoints más específicos por vista.
- Creer que GraphQL siempre es más rápido. Una consulta mal diseñada puede costar más que varias llamadas REST simples y bien cacheadas.
- Enviar todo por POST sin pensar en la caché. Rompe el caché HTTP tradicional; hay que resolverlo con IDs globales o consultas persistidas.
- Autorizar solo a nivel de endpoint en GraphQL. Con un único endpoint, la autorización tiene que aplicarse campo por campo en los resolvers.
Preguntas frecuentes
¿Cuándo conviene GraphQL en vez de REST?
GraphQL conviene sobre todo cuando varios clientes muy distintos entre sí, como una aplicación móvil, un sitio web y un panel de administración, consumen la misma información pero necesitan formas de datos distintas: con REST, atender bien a todos suele terminar en endpoints específicos para cada cliente o en respuestas genéricas que sobran para unos y faltan para otros, mientras que con GraphQL cada cliente declara en su propia consulta los campos que necesita, sin tocar el servidor. También rinde cuando una pantalla combina datos de varias entidades relacionadas, por ejemplo un usuario, sus posts y los comentarios de esos posts, y minimizar el número de viajes de ida y vuelta a la red importa, como en conexiones con latencia alta, porque una sola consulta reemplaza varias llamadas encadenadas. Por otro lado, GraphQL exige una inversión real: diseñar bien el esquema, resolver el problema N+1 con herramientas como DataLoader, y compensar la pérdida de la caché HTTP nativa con identificadores globales o consultas persistidas. Si el equipo no puede sostener esa inversión, o el caso de uso es simple y con un solo tipo de cliente, un REST bien diseñado suele rendir igual o mejor con mucho menos esfuerzo operativo.
¿GraphQL reemplaza a REST o se pueden combinar?
No reemplaza a REST: son dos estilos con objetivos distintos, y presentar a uno como la evolución natural del otro ignora sus compromisos reales. REST sigue siendo, para la enorme mayoría de las APIs públicas y de los servicios simples, la opción más sencilla de construir, documentar, cachear y depurar, precisamente porque cada recurso tiene su propia URL y su comportamiento se explica con los verbos HTTP que cualquier desarrollador conoce. GraphQL resuelve un problema puntual, que distintos clientes necesiten formas de datos distintas de la misma información sin multiplicar endpoints, y lo resuelve bien, pero a cambio de una infraestructura adicional: un esquema que mantener, resolvers que optimizar, y mecanismos propios de caché y de autorización. En la práctica, muchas organizaciones usan los dos al mismo tiempo dentro del mismo sistema: por ejemplo, una API REST pública y cacheable para integraciones externas y contenido de alto tráfico, y una capa GraphQL interna para paneles con necesidades de datos más variables. También es común que una capa GraphQL se construya encima de servicios REST ya existentes, como una fachada que agrega y da forma a los datos para el cliente final. La pregunta correcta no es cuál va a ganar, sino qué necesidad concreta resuelve cada uno en cada punto del sistema.
¿Por qué GraphQL tiene problemas de caché si se supone que es más eficiente?
GraphQL es más eficiente en la cantidad de datos que viajan en cada respuesta, porque evita la sobre-obtención, pero eso es independiente de si esa respuesta se puede cachear con los mecanismos estándar del protocolo HTTP, y ahí es donde pierde frente a REST. En REST, cada recurso tiene su propia URL, por ejemplo GET /api/usuarios/42, y el método GET está definido como cacheable por el RFC 9110, la especificación de semántica HTTP del IETF: navegadores, proxies y redes de distribución de contenido pueden guardar esa respuesta exacta y reutilizarla sin volver a golpear el servidor. GraphQL, en cambio, suele exponer un único endpoint y enviar todas las consultas, incluidas las de solo lectura, por el método POST, que el protocolo no trata como cacheable por defecto. Como distintas consultas, incluso si piden datos parecidos, llegan todas al mismo endpoint con cuerpos distintos, no hay una URL fija que un caché HTTP pueda usar como clave. La comunidad de GraphQL documenta paliativos, como exponer identificadores globales por objeto para que el propio cliente arme una caché en memoria, algo que hacen bibliotecas como Apollo Client o Relay, o servir consultas persistidas, versiones ya registradas de una consulta identificadas por un hash corto, por GET, recuperando así la cacheabilidad a costa de un paso extra que REST no necesita.
¿Qué es el problema N+1 y cómo se soluciona?
El problema N+1 aparece cuando resolver una lista de N elementos obliga a hacer una consulta adicional a la base de datos por cada uno de ellos para completar un dato relacionado, en lugar de traer todo junto: si una consulta devuelve 20 posts y el servidor busca el autor de cada post con una consulta separada, son 20 consultas más la consulta inicial que trajo los posts, 21 en total. No es un problema exclusivo de GraphQL: cualquier código que recorra una lista y dispare una consulta por elemento, sea en REST o en GraphQL, puede caer en lo mismo. Pero en GraphQL es especialmente visible y frecuente, porque el cliente puede anidar relaciones a cualquier profundidad en una sola consulta, y cada nivel de anidamiento puede multiplicar las consultas del nivel anterior si no se hace nada al respecto. La solución estándar, que documenta la propia GraphQL Foundation, es una utilidad llamada DataLoader: agrupa, hace batching de, las claves pedidas durante el mismo ciclo de vida de la petición en una sola llamada a la base de datos, y además deduplica, de modo que si tres posts distintos piden el mismo autor, ese autor se busca una única vez. Sin DataLoader u otra estrategia de agrupación equivalente, una API con datos anidados puede volverse, bajo carga real, más lenta que la misma funcionalidad resuelta con unas pocas llamadas REST bien escritas.
¿Es verdad que GraphQL no necesita versionar la API?
Es cierto en un sentido concreto y limitado, no de forma absoluta. GraphQL, según sus propias buenas prácticas documentadas en graphql.org, evita versionar la API completa como suele hacer REST con rutas del tipo /v1 y /v2. La razón de fondo es que en GraphQL el cliente declara explícitamente qué campos quiere recibir, así que agregar un campo o un tipo nuevo al esquema no rompe a ningún cliente existente, porque nadie que no lo pida se ve afectado por su existencia. Cuando un campo queda obsoleto, en lugar de eliminarlo de un día para el otro se lo marca con la directiva @deprecated, indicando el reemplazo recomendado, y se lo mantiene funcionando durante un tiempo mientras los clientes migran a su propio ritmo a los campos nuevos. Eso cubre el caso más común de evolución de una API: agregar capacidades sin romper lo que ya existe. Pero no cubre todos los cambios posibles: si hace falta modificar el tipo de un campo existente, cambiar su significado o eliminar algo que todavía se usa, eso sigue siendo un cambio disruptivo en GraphQL igual que en REST, y @deprecated no lo resuelve por sí solo. En definitiva, GraphQL cambia la estrategia de versionado, de versionar rutas completas a evolucionar un esquema de forma aditiva, pero no elimina la necesidad de pensar con cuidado los cambios que rompen contratos existentes.
¿GraphQL es más difícil de asegurar que REST?
No es que sea inherentemente más inseguro, pero sí exige pensar la autorización de una manera distinta y, en algunos aspectos, más fina. En REST, cada endpoint suele tener su propia capa de autorización: es sencillo aplicar una regla que exija que solo un administrador pueda usar DELETE /api/usuarios/42, porque ese endpoint hace una sola cosa concreta. En GraphQL, en cambio, una única consulta puede combinar en el mismo pedido campos públicos junto con campos privados o sensibles de la misma entidad, así que la autorización no se puede resolver a nivel de un endpoint único: tiene que aplicarse dentro de cada resolver, campo por campo, verificando en cada uno si quien consulta tiene permiso para ese dato puntual. Esto agrega trabajo de diseño que en REST muchas veces queda implícito en la propia estructura de rutas. A esto se suma que, al aceptar consultas arbitrariamente anidadas, una API GraphQL mal protegida puede ser blanco de consultas excesivamente profundas o costosas pensadas para sobrecargar el servidor, por lo que conviene limitar la profundidad y la complejidad permitidas. Ninguno de estos riesgos implica que GraphQL sea una mala elección; simplemente hay que diseñar la autenticación, los permisos y las validaciones con ese modelo en mente, algo que la guía de seguridad de APIs REST del portal desarrolla en detalle y que aplica, con ajustes, a los dos estilos.
Fuentes
Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 29 de julio de 2026.
Aportes de la comunidad Underc0de
- Underc0de, foro. Sección Programación. No existe, por el momento, un hilo específico sobre GraphQL en el foro: las discusiones de la sección tratan sobre todo de APIs REST. Esta guía no reorganiza un aporte previo de la comunidad sobre este tema puntual.
Documentación oficial
- GraphQL Foundation. Especificación de GraphQL, edición de septiembre de 2025. Primera edición completa desde octubre de 2021; define el lenguaje de consulta y el esquema.
- GraphQL Foundation. Learn GraphQL. Conceptos base del lenguaje de consulta y del esquema.
- GraphQL Foundation. Performance. Documentación oficial del problema N+1 y de DataLoader.
- GraphQL Foundation. Caching. Por qué GraphQL no cachea igual que REST y qué paliativos existen.
- GraphQL Foundation. Best Practices — Versioning. Por qué GraphQL evita versionar la API completa.
- IETF. RFC 9110 — HTTP Semantics. Define qué métodos HTTP son cacheables y bajo qué condiciones.
- R. Fielding (University of California, Irvine). Architectural Styles and the Design of Network-based Software Architectures, cap. 5 (REST). Fuente primaria de las restricciones arquitectónicas de REST.