---
term: 'Overfetching & Underfetching'
seoTitle: 'Overfetching y Underfetching: Causas, Costos y Soluciones'
headline: '¿Qué son el overfetching y el underfetching?'
slug: overfetching-y-underfetching
category: api-realtime
shortDefinition: 'Overfetching es un problema de API donde las respuestas traen más datos de los que el cliente necesita; underfetching fuerza solicitudes extra para completar.'
relatedTerms:
  - api-payload-optimization
  - n-plus-one-query-problem
  - graphql-vs-rest
  - rest-api
contrastsWith:
  - graphql-vs-rest
aboutTerms:
  - 'Overfetching'
  - 'Underfetching'
faq:
  - question: '¿Qué es el overfetching?'
    answer: 'Una API devuelve más datos de los que el cliente necesita para la tarea en cuestión — una pantalla de perfil que renderiza tres campos recibe cuarenta. El desperdicio se paga cuatro veces: serialización en el servidor, transferencia por la red, parsing en el cliente y, en mobile, batería y datos del plan. También puede exponer campos que ningún cliente debería ver.'
  - question: '¿Qué es el underfetching?'
    answer: 'Un solo endpoint no devuelve datos suficientes para renderizar la pantalla, así que el cliente hace solicitudes adicionales para armarla. Cada llamada extra es un round trip completo de red; cuando las llamadas son secuenciales — traer la lista y luego los detalles ítem por ítem — la latencia se compone en el problema de solicitudes N+1.'
  - question: '¿Cuál es la diferencia entre overfetching y underfetching?'
    answer: 'La dirección. Overfetching significa que cada respuesta carga de más — el costo es bytes; underfetching significa que cada respuesta carga de menos — el costo es round trips. Ambos crecen de la misma raíz: formas de respuesta fijas, diseñadas una vez, consumidas por pantallas con necesidades distintas. Muchas APIs cometen los dos al mismo tiempo, en la misma pantalla.'
  - question: '¿GraphQL resuelve el overfetching y el underfetching?'
    answer: 'En gran parte, en la capa HTTP: los selection sets traen solo los campos pedidos y las queries anidadas reúnen datos relacionados en una solicitud. Pero no es automático — los clientes que piden conjuntos generosos de campos recrean el overfetching, y los resolvers ingenuos recrean el underfetching contra la base de datos como N+1 de resolver, que los loaders con batching existen para corregir.'
  - question: '¿Cómo evitar el overfetching en una API REST?'
    answer: 'Los sparse fieldsets son la solución directa: un parámetro fields (o select() en los query builders de los SDKs) que proyecta solo las columnas que la pantalla renderiza. La paginación acota el tamaño de las listas, los endpoints a la medida casan respuestas con pantallas reales y la compresión encoge lo que queda — aunque comprimir el exceso es mitigación, no cura.'
  - question: '¿Cómo corregir el underfetching sin migrar a GraphQL?'
    answer: 'Parámetros de expansión — include o expand — que embeben objetos relacionados en una respuesta; documentos compuestos que envían un recurso con sus asociaciones; endpoints compuestos que agregan las necesidades de una pantalla en el servidor; y, en lo arquitectónico, una capa backend-for-frontend que hace el ensamblado cerca de los datos, no a través de una red móvil.'
  - question: '¿Cómo se relaciona el problema N+1 con el underfetching?'
    answer: 'N+1 es underfetching a escala: una solicitud para una lista de N ítems y luego N solicitudes de seguimiento por los detalles de cada uno. La misma forma recurre en cada capa — clientes HTTP contra endpoints REST, resolvers de GraphQL contra la base de datos, ORMs cargando relaciones en lazy dentro de un loop — y la solución es siempre la misma idea: agrupar los N en uno.'
  - question: '¿Por qué el overfetching es un riesgo de seguridad?'
    answer: 'Los campos que una pantalla nunca renderiza igual cruzan la red — y cualquiera puede abrir las herramientas de desarrollador y leerlos. Flags internas, correos de otros usuarios y datos de costos se fugan así; las taxonomías de seguridad lo clasifican como exposición excesiva de datos, y el principio de mínimo privilegio aplica a los cuerpos de respuesta tanto como a los permisos.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'GraphQL specification — selection sets'
    url: 'https://spec.graphql.org/October2021/#sec-Selection-Sets'
  - name: 'JSON:API specification — sparse fieldsets'
    url: 'https://jsonapi.org/format/#fetching-sparse-fieldsets'
  - name: 'OWASP API Security Top 10'
    url: 'https://owasp.org/API-Security/'
  - name: 'Backends For Frontends pattern — Sam Newman'
    url: 'https://samnewman.io/patterns/architectural/bff/'
cta:
  title: 'Trae exactamente lo que la pantalla necesita'
  text: 'Las queries de Back4app aceptan select() e include() en todos los SDKs — sparse fieldsets y relaciones en un solo round trip sin diseñar un solo endpoint — más una API GraphQL cuando los clientes quieren moldear las respuestas ellos mismos.'
  linkText: 'Empieza gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-09-04'
translationKey: overfetching-underfetching
---

**Overfetching es un problema de API donde las respuestas traen más datos de los que el cliente necesita; underfetching fuerza solicitudes extra para completar.** Son los modos de falla gemelos de las formas de respuesta fijas — uno desperdicia bytes, el otro desperdicia round trips — y la mayoría de las APIs comete ambos en la misma pantalla: cada respuesta demasiado gorda, y demasiadas respuestas.

## Puntos clave

| Pregunta | Respuesta |
| --- | --- |
| Overfetching | De más por respuesta — ancho de banda, parsing, batería, exposición |
| Underfetching | De menos por respuesta — round trips extra, cascadas, N+1 |
| La causa raíz | Formas fijas de endpoint encontrándose con pantallas de necesidades distintas |
| Soluciones REST | Sparse fieldsets · params include/expand · paginación · endpoints compuestos |
| La respuesta de GraphQL | Selection sets — con salvedades honestas en la capa de resolvers |

## Una pantalla, tres formas de traerla

Una lista de posts que renderiza cada título con el nombre de su autor:

```text
Overfetching                          Underfetching
GET /posts                            GET /posts            (solo IDs de autor)
→ 20 posts × 40 campos                GET /users/11  ┐
→ ~160 KB enviados,                   GET /users/12  │  20 llamadas más —
  ~6 KB renderizados (96% desperdicio)  …            │  la cascada N+1
                                      GET /users/30  ┘

La query con forma
GET /posts?fields=title,summary,author&include=author&limit=20
→ 20 posts × 3 campos + sus autores — un round trip, ~7 KB
```

La misma query con forma como código de SDK — proyección y relación en una solicitud:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// One shaped query: no overfetch, no underfetch
const query = new Parse.Query('Post');
query.select('title', 'summary', 'author'); // only what the screen renders
query.include('author');                    // related object, same response
query.limit(20);                            // bounded page
const posts = await query.find();
// 1 round trip — not 1 list call + 20 author calls (N+1)
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// One shaped query: no overfetch, no underfetch
final query = QueryBuilder<ParseObject>(ParseObject('Post'))
  ..keysToReturn(['title', 'summary', 'author']) // only what the screen renders
  ..includeObject(['author'])                    // related object, same response
  ..setLimit(20);                                // bounded page
final response = await query.query();
// 1 round trip — not 1 list call + 20 author calls (N+1)
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// One shaped query: no overfetch, no underfetch
let query = Post.query()
  .select("title", "summary", "author") // only what the screen renders
  .include("author")                    // related object, same response
  .limit(20)                            // bounded page
query.find { result in
  // 1 round trip — not 1 list call + 20 author calls (N+1)
  if case .success(let posts) = result { render(posts) }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// One shaped query: no overfetch, no underfetch
val query = ParseQuery.getQuery<ParseObject>("Post")
query.selectKeys(listOf("title", "summary", "author")) // only what the screen renders
query.include("author")                                // related object, same response
query.limit = 20                                       // bounded page
query.findInBackground { posts, e -> if (e == null) render(posts) }
// 1 round trip — not 1 list call + 20 author calls (N+1)
```

## ¿Qué es el overfetching?

El overfetching es la versión en la capa de API del `SELECT *`: el endpoint devuelve su representación fija completa sin importar lo que el llamador renderiza. Los costos se apilan en capas. El servidor serializa campos que nadie lee; la red los carga — y ahí es donde sufre el mobile, ya que el tiempo de transferencia escala con bytes sobre ancho de banda limitado y cada kilobyte innecesario gasta datos del plan y batería de radio; luego el cliente parsea todo, porque la descompresión ocurre antes del renderizado y una respuesta inflada es trabajo de parsing inflado incluso cuando la compresión la escondió en la red.

El costo más silencioso es la exposición. Un campo de respuesta que la UI nunca muestra sigue a un clic de las herramientas de desarrollador de ser leído — flags internas, correos de otros usuarios, datos de márgenes. El [OWASP API Security Top 10](https://owasp.org/API-Security/) lo registra como exposición excesiva de datos (broken object property level authorization): el mínimo privilegio aplica a los cuerpos de respuesta, y un campo que ningún cliente debería ver no debería serializarse en primer lugar.

## ¿Qué es el underfetching?

El underfetching es la deficiencia opuesta: la forma fija del endpoint carga de menos, así que el cliente se vuelve un integrador — trae la lista, luego el autor de cada ítem, luego quizá el avatar de cada autor. Cada llamada extra es un round trip completo, y los round trips son la moneda de la que las redes móviles son más pobres: a unos realistas 100 ms por solicitud, una lista de 20 ítems resuelta en secuencia gasta dos segundos *solo en latencia*, antes de un byte de matemática de payload.

A escala, esta cascada tiene nombre — el [problema de solicitudes N+1](/glossary/es/problema-n-mas-1/): una llamada por N ítems, N llamadas por sus detalles. La forma es fractal; recurre dondequiera que una interfaz fija se encuentra con datos relacionales — clientes HTTP contra endpoints REST, resolvers de GraphQL contra la base de datos, ORMs abriéndose paso con lazy loading dentro de un loop — y la cura es siempre alguna forma de agrupar los N en uno.

```mermaid
flowchart LR
  accTitle: Cascada de underfetching versus una query con forma
  accDescr: Con underfetching, el cliente hace una solicitud por una lista y luego una solicitud secuencial por ítem, multiplicando la latencia de round trips. Una query con forma devuelve la lista con sus datos relacionados en un solo round trip.
  subgraph W["Underfetching: 1 + N round trips"]
    L["GET /posts"] --> U1["GET /users/11"] --> U2["GET /users/12"] --> U3["… × 20"]
  end
  subgraph S["Con forma: 1 round trip"]
    Q["GET /posts?fields=…&include=author"]
  end
```

## Overfetching vs. underfetching

| | Overfetching | Underfetching |
| --- | --- | --- |
| Síntoma | Respuestas llenas de campos sin renderizar | Pantallas armadas a partir de muchas llamadas |
| Unidad de desperdicio | Bytes (y tiempo de parsing) | Round trips (y latencia) |
| Peor en | Redes con plan de datos, lentas, limitadas por batería | Redes de alta latencia — las cascadas se componen |
| Detección | Compara campos devueltos vs. campos renderizados | Cuenta solicitudes por pantalla en la pestaña de red |
| Solución directa | Sparse fieldsets / proyección | Params de expansión, endpoints compuestos |
| Escalada | Exposición excesiva de datos (seguridad) | Tormentas de solicitudes N+1 (escala) |

El diagnóstico es misericordiosamente mecánico, y ningún explicador de rankings lo dice: abre la pestaña de red en una pantalla. Muchas solicitudes para una vista es underfetching; respuestas grandes cuyos campos no encuentras en la UI es overfetching. Las analíticas por endpoint generalizan la auditoría — tamaño de payload p95 por endpoint, solicitudes por sesión por pantalla.

## Cómo corregir ambos sin salir de REST

La migración a GraphQL no es el primer recurso; las convenciones REST maduras cubren la mayor parte de la distancia:

- **Sparse fieldsets** — un parámetro `fields` que proyecta la representación: estandarizado como [sparse fieldsets de JSON:API](https://jsonapi.org/format/#fetching-sparse-fieldsets), reflejado en opciones de query estilo `$select` y en los builders `select()` de los SDKs. La solución del overfetching en el origen.
- **Parámetros de expansión** — `include=author,comments` embebe recursos relacionados en la misma respuesta (documentos compuestos), convirtiendo una cascada N+1 en una solicitud. La solución del underfetching en el origen.
- **Paginación** — acota la dimensión de lista del overfetching; las colecciones sin límite son bugs de payload que crecen con la adopción.
- **Endpoints a la medida y compuestos** — cuando una pantalla siempre necesita el mismo agregado, dale un endpoint que devuelva exactamente ese agregado, armado en el servidor, donde la latencia entre servicios es de microsegundos, no de round trips móviles.
- **Un backend-for-frontend** — la versión arquitectónica del mismo movimiento: una capa delgada por cliente que habla con APIs internas generosas y sirve a cada frontend exactamente su forma ([el patrón BFF de Sam Newman](https://samnewman.io/patterns/architectural/bff/)).
- **Compresión** — honesto último lugar: encoge la transmisión, no el desperdicio; el costo de parsing y la exposición le sobreviven intactos.

## ¿GraphQL lo resuelve?

En gran parte — y el "en gran parte" vale la pena conocerlo. Los [selection sets](https://spec.graphql.org/October2021/#sec-Selection-Sets) hacen de la lista de campos del cliente *la solicitud misma*, lo que jubila al overfetching clásico, y las queries anidadas arman los datos relacionados en un round trip, lo que jubila al underfetching clásico. Exactamente por eso el debate [GraphQL vs. REST](/glossary/es/graphql-vs-rest/) empieza con estas dos palabras.

Las salvedades viven una capa más abajo. Los clientes que copian y pegan queries generosas hacen overfetching por hábito — nada garantiza que una query case con lo que un componente renderiza, a menos que el equipo adopte fragments por componente. Y una cadena ingenua de resolvers *hace underfetching contra la base de datos*: una query de 20 posts con autores se vuelve 1 + 20 lecturas en la base, a menos que los resolvers agrupen a través de una capa de loading — el mismo N+1, reubicado. GraphQL mueve el problema a una capa que tú controlas, lo cual es progreso genuino; no lo borra.

## Casos de uso comunes

Dónde aparecen primero los dos problemas (y sus soluciones):

- **Pantallas de lista en mobile** — el overfetch canónico: filas completas enviadas para renderizar tres campos por celda.
- **Pantallas de detalle con relaciones** — post + autor + comentarios: cascadas de underfetch, salvo que se expandan o se compongan.
- **Mercados de redes lentas** — ambos problemas gravados a la tasa máxima; las queries con forma como accesibilidad.
- **Dashboards** — pantallas agregadas que o hacen overfetching de filas crudas o underfetching a través de cinco servicios; territorio de BFF.
- **APIs públicas con consumidores diversos** — una forma fija no puede servir a la carátula de un reloj y a una consola de admin; los parámetros de proyección y expansión dejan que cada llamador ajuste.

## ¿Qué problema tienes? Matriz de decisión

| Evidencia en la pestaña de red | Diagnóstico | Primera solución |
| --- | --- | --- |
| Una solicitud, respuesta grande, pocos campos renderizados | Overfetching | Sparse fieldsets / `select()` |
| Muchas solicitudes secuenciales por pantalla | Underfetching | `include` / params de expansión |
| Las solicitudes escalan con el largo de la lista | N+1 | Batch: expansión o endpoint compuesto |
| Grandes y muchas a la vez | Ambos — común | Query con forma o selección GraphQL |
| Campos de respuesta que preferirías que no salieran del servidor | Exposición | Recorta la serialización en el servidor, no en el cliente |

## Limitaciones y trade-offs

- **La proyección acopla clientes a listas de campos.** Un param `fields` que se desalinea de la UI causa bugs de datos faltantes; tipos generados y review mantienen honestas las selecciones.
- **La expansión puede sobrecorregir.** Un `include=comments` en una lista caliente puede enviar megabytes de relaciones embebidas — las respuestas expandidas necesitan su propia paginación y límites de profundidad.
- **Los endpoints a la medida se multiplican.** Los endpoints por pantalla arreglan el fetching y crean una cuenta de mantenimiento por proliferación de endpoints; los BFF concentran esa proliferación en una capa con dueño, al costo de operarla.
- **La flexibilidad en el servidor tiene precio.** La proyección y la expansión arbitrarias complican el caché (cada forma es una clave de caché) y la autorización (cada combinación debe ser segura de servir).
- **Los problemas también son señales de modelado.** Una pantalla que necesita recortes profundos o cinco includes puede estar diciéndote que las formas de los recursos están mal — a veces la solución es [el modelo de datos](/glossary/es/modelado-de-datos/), no el fetch.

## Overfetching y underfetching en Back4app

Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. Ambas soluciones vienen como primitivos de query en todos los SDKs — las pestañas de código de arriba son el patrón completo: `select()` es el sparse fieldset, `include()` es el parámetro de expansión, y juntos convierten una cascada 1 + N en un round trip con forma contra la [API REST](/glossary/es/api-rest/) generada automáticamente. Cuando los clientes quieren control total de la forma de la respuesta, los mismos datos se consultan vía selection sets de GraphQL; cuando una pantalla necesita un agregado en el servidor, una función de Cloud Code es un endpoint compuesto que escribes en un archivo. El fetch casa con la pantalla — por idioma, no por rediseño de endpoints.
