Plantilla de Política de Deprecación de GraphQL
Plantilla de política para deprecar campos, tipos y valores enum de GraphQL sin romper clientes, con cronogramas, seguimiento de uso y ejemplos de migración.
Overview
Eliminar un campo de GraphQL sin avisar rompe todos los clientes que todavía lo consultan — y como los esquemas GraphQL no tienen una convención de versionado, la deprecación es la única salida segura. Esta plantilla es una política lista para copiar y adaptar para retirar campos, tipos, argumentos y valores enum: cómo anunciar el cambio, cuánto tiempo tienen los consumidores, cómo medir el uso restante y cuándo la eliminación es realmente segura.
Adapta los días y los porcentajes de rate limit a la tolerancia de tu organización, pero mantén la secuencia intacta: primero anunciar, después medir y al final eliminar. Los equipos que se saltan la fase de medición suelen descubrir en producción que un dashboard interno o un cron job olvidado todavía depende del campo.
Antes de deprecar cualquier elemento, pasa el esquema por el Checklist de Revision de Schema GraphQL — algunas “deprecaciones” son en realidad rediseños evitables.
Cuándo usar esta política
Aplica esta política siempre que un elemento del esquema vaya a eliminarse:
- Renombrar o reestructurar campos — por ejemplo, dividir
User.nameenfirstNameylastName. - Sustituir una lista plana por una conexión paginada — depreca el campo antiguo mientras los clientes migran a paginación por cursor.
- Consolidar tipos —
ProductV2reemplazando aProduct, o dos interfaces que se fusionan en una. - Retirar valores enum — integrar un estado como
RETURNEDdentro deCANCELLEDcon un argumento de motivo. - Eliminar mutaciones o argumentos — una mutación amplia
updateUserreemplazada por otras granulares comoupdateUserProfile. - Retirar funcionalidades experimentales — cualquier cosa lanzada tras un flag beta que nunca se estabilizó.
No la uses para cambios puramente aditivos — campos nuevos, valores enum nuevos o ampliar un tipo de entrada son compatibles hacia atrás y solo necesitan una entrada en el changelog. En grafos federados, el cronograma debe coordinarse con los propietarios de cada subgrafo; la Guía Completa de GraphQL Federation cubre ese flujo entre subgrafos.
1. Ámbito de la deprecación
1.1 Qué se puede deprecar
| Elemento | Método de deprecación | ¿Rompe al eliminarse? |
|---|---|---|
| Campo | Directiva @deprecated en el campo | Sí |
| Tipo | Directiva @deprecated en el tipo | Sí |
| Argumento | Directiva @deprecated en el argumento | Sí |
| Valor enum | Directiva @deprecated en el valor enum | Sí |
| Campo de entrada | Directiva @deprecated en el campo de entrada | Sí |
| Scalar personalizado | Documentación más guía de migración | Sí |
| Directiva | Documentación más guía de migración | Sí |
| Non-null → null | Cambio de esquema (no requiere directiva) | No |
| Null → non-null | No permitido — crea un campo nuevo | N/A |
1.2 Qué no se puede deprecar
Algunos cambios son incompatibles por naturaleza, así que deprecar el elemento antiguo no los hace seguros. Estos siempre requieren un elemento nuevo junto al antiguo:
- Cambiar el tipo de un campo (
String→Int) — añade un campo nuevo con el nuevo tipo. - Convertir un campo nullable en non-null — añade un campo non-null nuevo.
- Eliminar la implementación de una interface — publica un tipo nuevo.
- Cambiar el tipo de un argumento — añade un argumento nuevo o una mutación nueva.
2. Cronograma de deprecación
La política usa un cronograma de cinco fases. Cada fase condiciona a la siguiente: un elemento deprecado solo avanza cuando su uso cae por debajo del umbral de esa fase.
2.1 Cronograma estándar
Fase 1: Anunciar (Día 0)
- Añadir la directiva @deprecated con motivo y reemplazo
- Publicar el aviso de deprecación en el changelog
- Notificar a todos los consumidores conocidos por email/Slack
- Añadir la deprecación a la documentación del esquema
Fase 2: Monitorizar (Día 0 - Día 90)
- Registrar el uso del elemento deprecado
- Informes de uso semanales al equipo de API
- Recordatorios a clientes de alto uso cada 30 días
- Ofrecer soporte de migración
Fase 3: Avisar (Día 90 - Día 180)
- Añadir aviso de deprecación en las extensions de la respuesta
- Aplicar rate limit al elemento deprecado (reducir un 50%)
- Escalar a dirección si el uso supera el 10% del original
Fase 4: Aviso final (Día 180 - Día 210)
- Aviso final a todos los consumidores restantes
- Rate limit agresivo (reducir un 90%)
- Fijar la fecha de eliminación en el motivo de deprecación
Fase 5: Eliminar (Día 210+)
- Eliminar del esquema solo si el uso es 0 durante 30 días seguidos
- Publicar la eliminación en el changelog
- Mantener la guía de migración disponible 90 días tras la eliminación
2.2 Cronograma acelerado
Reserva la vía de 30 días para vulnerabilidades de seguridad y fugas de datos — usarla para limpieza ordinaria enseña a los consumidores a ignorar tus cronogramas.
Fase 1: Anunciar + Avisar (Día 0)
- Deprecar inmediatamente
- Notificar a todos los consumidores
- Añadir avisos en la respuesta
Fase 2: Rate limit (Día 0 - Día 30)
- Rate limit agresivo desde el día 1
- Informes de uso diarios
Fase 3: Eliminar (Día 30+)
- Eliminar si el uso es inferior al 1% del original
- Documentar el problema de seguridad en el changelog
2.3 Ajustar el cronograma
Los valores por defecto asumen una API pública con desarrolladores externos. Comprímelos o extiéndelos según quién consuma el esquema:
| Tipo de consumidor | Mínimo sugerido | Por qué |
|---|---|---|
| Solo servicios internos | 30–90 días | Controlas ambos extremos; un recordatorio en Slack llega a todos los responsables |
| Integraciones de partners / B2B | 180–210 días | Las revisiones de contrato y los ciclos de release ralentizan las migraciones |
| API pública para desarrolladores | 210–365 días | Consumidores desconocidos, apps en revisión, clientes abandonados que siguen funcionando |
| Clientes de sectores regulados | 12+ meses | Las ventanas de congelación de cambios y auditoría bloquean migraciones a mitad de año |
Elijas la ventana que elijas, nunca acortes un cronograma ya publicado de forma retroactiva — adelantar una fecha de eliminación anunciada rompe justo la confianza que esta política existe para crear.
3. Formato de la directiva de deprecación
La directiva @deprecated está definida por la propia especificación de GraphQL, así que todo ecosistema de herramientas compatible la entiende — GraphiQL tacha los campos deprecados, el codegen emite avisos y los generadores de documentación los marcan automáticamente. Por eso el texto del motivo lleva el peso real: es el mensaje que esas herramientas muestran.
3.1 Formato estándar
type User {
id: ID!
# Campos deprecados
name: String! @deprecated(
reason: "Use firstName and lastName. Will be removed on {YYYY-MM-DD}. See migration guide: /docs/migrations/user-name-split"
)
email: String! @deprecated(
reason: "Use contactEmail for display and primaryEmail for system. Will be removed on {YYYY-MM-DD}."
)
# Campos de reemplazo
firstName: String!
lastName: String!
contactEmail: String!
primaryEmail: String!
}
enum OrderStatus {
PENDING
CONFIRMED
SHIPPED
DELIVERED
CANCELLED
REFUNDED
RETURNED @deprecated(
reason: "Use CANCELLED with reason RETURNED. Will be removed on {YYYY-MM-DD}."
)
}
3.2 Formato del motivo de deprecación
Formato obligatorio:
"{instrucciones de reemplazo}. Will be removed on {YYYY-MM-DD}. {opcional: enlace a la guía de migración}"
Ejemplos:
"Use firstName and lastName. Will be removed on 2027-03-01."
"Use orders connection with pagination. Will be removed on 2027-04-15. See: /docs/migrations/orders-pagination"
"Use ProductV2 type. Will be removed on 2027-06-01. See: /docs/migrations/product-v2"
El motivo es la única señal de deprecación que la mayoría de los consumidores verá jamás — la introspección lo muestra en GraphiQL, Apollo Studio Explorer y los avisos de codegen. Motivos vagos como "deprecated, don't use" generan tickets de soporte en lugar de migraciones.
4. Seguimiento de uso
4.1 Implementación del seguimiento (Apollo Server 4)
import type { ApolloServerPlugin } from '@apollo/server';
import type { GraphQLSchema } from 'graphql';
import { parse, visit, visitWithTypeInfo, TypeInfo } from 'graphql';
// Recorre el documento de la query contra el esquema y recoge
// cada campo seleccionado que lleva un deprecationReason.
function extractDeprecatedFields(query: string, schema: GraphQLSchema) {
const typeInfo = new TypeInfo(schema);
const found: Array<{ name: string; parentType: string; reason: string }> = [];
visit(
parse(query),
visitWithTypeInfo(typeInfo, {
Field(node) {
const fieldDef = typeInfo.getFieldDef();
if (fieldDef?.deprecationReason) {
found.push({
name: `${typeInfo.getParentType()?.name}.${node.name.value}`,
parentType: String(typeInfo.getParentType()?.name),
reason: fieldDef.deprecationReason,
});
}
},
}),
);
return found;
}
const deprecationTracker: ApolloServerPlugin = {
async requestDidStart({ request, schema }) {
return {
async willSendResponse({ response }) {
const deprecated = extractDeprecatedFields(request.query ?? '', schema);
if (deprecated.length === 0 || response.body.kind !== 'single') return;
// Muestra el aviso dentro de la propia respuesta GraphQL.
response.body.singleResult.extensions = {
...response.body.singleResult.extensions,
deprecations: deprecated.map((f) => ({
field: f.name,
reason: f.reason,
})),
};
for (const field of deprecated) {
await analytics.track('deprecated_field_used', {
field: field.name,
type: field.parentType,
operationName: request.operationName ?? 'anonymous',
client: request.http?.headers.get('x-client-id') ?? 'unknown',
timestamp: new Date().toISOString(),
});
}
},
};
},
};
Dos detalles importan aquí. Primero, la cabecera x-client-id es lo que convierte conteos brutos en una lista accionable de consumidores — sin ella sabes que un campo se usa pero no a quién contactar. Las cabeceras de client awareness de Apollo (apollographql-client-name, apollographql-client-version) cumplen la misma función si tu gateway ya las exige. Segundo, escribir el aviso en extensions hace visible la deprecación en el cuerpo de la respuesta, que es donde los desarrolladores miran — la mayoría de los consumidores nunca ejecutan introspección en producción.
Si usas un gateway en lugar de un servidor monolítico, la misma idea aplica en la capa del router: GraphOS Studio informa del uso de campos por cliente de serie, y GraphQL Hive registra la cobertura de campos deprecados. Para CI, graphql-inspector validate (o audit) puede fallar una pull request cuando un documento del cliente selecciona un campo deprecado, lo que detecta usos nuevos antes de que lleguen a producción.
4.2 Plantilla de informe de uso
Informe de uso de campos deprecados — Semana del {YYYY-MM-DD}
Field | Type | Usage Count | Top Clients
-------------------------|----------|-------------|------------------
User.name | User | 1,234 | mobile-app, admin
User.email | User | 567 | mobile-app
OrderStatus.RETURNED | Enum | 89 | reporting-service
Product.legacyPrice | Product | 12 | legacy-integration
Total de queries deprecadas: 1,902
Tendencia: 15% menos que la semana pasada
Elegible para eliminación: Product.legacyPrice (uso < 50 durante 30 días)
5. Plan de comunicación
Los avisos de deprecación fallan en dos direcciones: anunciar una vez y desaparecer, o avisar tan a menudo que los consumidores silencian el canal. La cadencia siguiente espacia los puntos de contacto a lo largo del cronograma — cada uno llega cuando hay algo nuevo que decir (el uso sigue alto, el rate limit está a punto de empezar, la fecha cambió).
5.1 Canales de comunicación
| Audiencia | Canal | Frecuencia |
|---|---|---|
| Equipos internos | Canal de Slack #api-deprecations | Al anunciar + mensual |
| Clientes externos | Email a desarrolladores registrados | Al anunciar + días 30/90/180 |
| Público | Página de changelog | Al anunciar + al eliminar |
| Documentación de la API | Documentación del esquema | Continuo |
| Respuesta GraphQL | extensions.deprecations | Cada petición |
| Portal de desarrolladores | Panel de deprecaciones | Continuo |
5.2 Plantilla de email
Subject: [Action Required] GraphQL API Deprecation Notice — {Field/Type Name}
Body:
The following GraphQL schema element has been deprecated:
Element: {field/type/enum name}
Type: {field/type/enum/argument}
Deprecated on: {date}
Removal date: {date}
Replacement: {replacement instructions}
Impact on your application:
{description of what breaks if not migrated}
Migration guide:
{link to migration documentation}
Current usage:
Your application uses this element {N} times per day.
Next steps:
1. Review the migration guide
2. Update your queries by {removal date}
3. Test with the new schema in staging
4. Contact api-support@company.com for help
Timeline:
- Day 0: Deprecation announced (today)
- Day 90: Rate limiting begins on deprecated element
- Day 180: Hard rate limiting (90% reduction)
- Day 210: Element removed from schema
La línea “Current usage” es lo que hace efectivo este email — decirle a un equipo que su app llama al campo deprecado 400 veces al día impacta de forma muy distinta a un aviso genérico. Si tu seguimiento aún no puede producir ese número, despliega el seguimiento primero y anuncia después.
6. Plantilla de guía de migración
6.1 Estructura de la guía de migración
## Migrating from {deprecated} to {replacement}
### What changed
{Description of what was deprecated and why}
### Before
```graphql
query {
user(id: "1") {
name
email
}
}
```
### After
```graphql
query {
user(id: "1") {
firstName
lastName
contactEmail
}
}
```
### Migration steps
1. Update all queries that select {deprecated field}
2. Update all response parsing logic
3. Update all tests
4. Deploy to staging and verify
5. Deploy to production
### Common issues
- **Issue**: {common problem}
**Fix**: {solution}
### Timeline
- Deprecated: {date}
- Rate limited: {date}
- Removed: {date}
7. Criterios de eliminación
7.1 Checklist de eliminación
- Periodo de deprecación completado (mínimo 210 días para el estándar, 30 para el acelerado)
- Uso en cero durante 30 días consecutivos
- Todos los clientes conocidos migrados
- Guía de migración publicada
- Aviso final enviado 30 días antes de la eliminación
- Entrada de changelog preparada
- Cambio de esquema revisado y aprobado
- Plan de rollback documentado
7.2 Proceso de eliminación
1. Verificar que el uso es 0 durante 30 días
2. Crear el PR que elimina el elemento deprecado
3. Incluir la entrada de changelog en el PR
4. Revisión del esquema por el equipo de API
5. Desplegar a staging
6. Verificar que no hay errores en staging durante 48 horas
7. Desplegar a producción
8. Monitorizar la tasa de errores durante 24 horas
9. Mantener la guía de migración disponible durante 90 días
10. Archivar los datos de seguimiento de la deprecación
Cero uso durante 30 días consecutivos es la puerta que más importa. Un campo deprecado que todavía recibe unas pocas llamadas suele ser una app móvil en una versión antigua o un servicio que alguien olvidó que poseía — revisa los IDs de cliente antes de asumir que ese tráfico está abandonado.
Cómo adoptar la política en tu organización
Publicar el documento de política es la parte fácil; hacerla operativa requiere unos pasos deliberados. El orden importa: instrumentación antes del anuncio, seguimiento antes de los plazos y una vía de escalado acordada antes de que llegue la primera petición de excepción:
- Publica la política donde los consumidores la leen de verdad. Ponla en tu portal de desarrolladores o en la documentación de la API, y enlázala desde cada aviso de deprecación y entrada de changelog.
- Instrumenta antes de anunciar. Despliega el plugin de seguimiento de uso y recoge dos semanas de datos base para que el primer email pueda incluir cifras reales por cliente.
- Monta un tracker de deprecaciones. Una hoja de cálculo o un proyecto de Linear con una fila por elemento deprecado — responsable, fecha de anuncio, fecha de eliminación, uso actual, estado — es suficiente.
- Automatiza el informe semanal. La tabla de uso de la sección 4.2 debería llegar al inbox o canal de Slack del equipo de API sin que nadie ejecute la query a mano.
- Bloquea la eliminación en CI. Un check de schema-diff que falle cuando se elimina un elemento no deprecado evita roturas accidentales; la Guía de Diseño de GraphQL API cubre la parte de revisión.
- Define una vía de escalado. Decide por adelantado quién aprueba extensiones del cronograma y quién puede autorizar la vía acelerada, o cada excepción se convierte en una negociación improvisada.
Espera que la primera deprecación saque a la luz carencias — IDs de cliente que faltan, una lista de contactos desactualizada, un consumidor que nadie recordaba. Es normal: la primera pasada por el cronograma es también la auditoría de tu propia instrumentación. Corrige las carencias a medida que aparezcan y la segunda deprecación irá notablemente más fina.
Errores comunes
- Deprecar sin medir antes. Anunciar una fecha de eliminación sin saber quién usa el campo produce extensiones de plazo — que enseñan a los consumidores que tus fechas son negociables.
- Tratar
@deprecatedcomo aviso suficiente. La directiva solo aparece en introspección y codegen; los clientes en producción nunca la ven. Lasextensionsde la respuesta y el contacto directo hacen el trabajo real. - Subestimar la eliminación de enums. Los valores enum quedan almacenados en bases de datos, cachés y builds de apps móviles.
OrderStatus.RETURNEDpuede seguir llegando en peticiones meses después de que tus queries dejen de seleccionarlo — registra también argumentos y variables, no solo el selection set. - Olvidar los campos de entrada.
@deprecatedfunciona en campos de input objects, pero muchos equipos solo anotan los tipos de salida. Los formularios del lado cliente siguen enviando el campo de entrada antiguo mucho después de que la salida esté limpia. - Dejar que deprecaciones “temporales” se pudran. Un elemento deprecado “hasta nuevo aviso” sin fecha ni responsable se convierte en deuda permanente del esquema. Toda deprecación necesita una fecha de eliminación, aunque sea conservadora.
- Reutilizar un nombre eliminado demasiado pronto. Una vez eliminado un campo, reserva el nombre al menos un ciclo de deprecación más — las persisted queries y los esquemas cacheados pueden resucitar el significado antiguo contra un campo nuevo con un tipo distinto.
Ver también
Preguntas frecuentes
¿Qué pasa si un cliente no puede migrar antes de la fecha de eliminación?
Concede extensiones caso a caso, pero pide primero un plan de migración con una fecha concreta. Prefiere extender el rate limit antes que mover la fecha de eliminación — un plazo que se retrasa indica que el cronograma nunca fue firme. Para clientes internos, escala a su engineering manager; para clientes externos críticos, amplía la ventana pero fija una fecha límite definitiva. Registra cada extensión en el tracker de deprecaciones para que las excepciones "temporales" sigan visibles.
¿Cómo depreco un campo que forma parte de una interface?
Pon @deprecated en el campo dentro de la definición de la interface y todos los tipos que la implementan heredan la señal. Cuando solo algunas implementaciones deban retirarlo, anota el campo en cada tipo por separado y lista los tipos afectados en el changelog — si no, los consumidores asumirán que toda la interface desaparece.
¿Puedo "des-deprecar" un campo?
Durante los primeros 30 días, sí: quita la directiva @deprecated y avisa a los consumidores de que la deprecación se retiró. Pasada esa ventana, revertirla confunde a quienes ya migraron — publica un campo nuevo con el mismo nombre y tipo. En cualquiera de los casos, escribe una entrada de changelog explicando la marcha atrás.
¿Cómo registro el uso de valores enum deprecados?
Los valores enum aparecen en argumentos y variables de la query en lugar del selection set, así que el seguimiento a nivel de campo los pierde. Analiza las variables de cada query entrante buscando el valor deprecado y registra los aciertos en el mismo pipeline de analítica que los campos. Informa del uso de enums por separado: el volumen suele ser menor, pero el impacto es mayor porque el valor suele estar persistido en las bases de datos de los clientes.
¿Qué pasa si necesito eliminar un campo antes del cronograma estándar?
La vía acelerada de 30 días existe solo para vulnerabilidades de seguridad y fugas de datos — anota la justificación de seguridad en el motivo de deprecación, avisa al equipo de seguridad y aplica rate limits agresivos desde el primer día. Para eliminaciones urgentes que no son de seguridad, comprime a 90 días con aprobación de dirección y contacto directo con todos los consumidores del tracker.
Recursos Relacionados
Checklist de Revision de Schema GraphQL
Checklist para revisar schemas GraphQL: naming conventions, type design, pagination, error handling, security, performance, deprecation y federation readiness con ejemplos de codigo y validation rules.
DocGuía de Diseño de GraphQL API
Plantilla de lineamientos internos de diseño de APIs GraphQL con estructura de schema, nombres, mutaciones, paginación, auth, rate limiting, versionado y federación.
GuideGuía Completa de GraphQL Federation
Construye APIs GraphQL unificadas con Apollo Federation. Cubre subgraphs, supergraph, resolución de entidades y despliegue de gateway.
DocPlantilla de Onboarding a GraphQL Federation
Plantilla para onboardear un servicio a un federated GraphQL graph: subgraph setup, entity definitions, resolver configuration, gateway integration, testing, deployment y monitoring con ejemplos de codigo.