GraphQL in Production · Security, Observability and Evolution
Observability for GraphQL
Per-operation and per-field metrics, tracing and error tracking.
HTTP-level metrics are useless when every request is POST /graphql 200. Instrument by operation name (rate, errors, latency percentiles), track field-level resolver timings to find slow fields, export OpenTelemetry spans for parsing, validation and resolvers (sampled — per-field spans are expensive), and record errors[] with extensions.code. Schema registries (Apollo GraphOS, Hive) aggregate field usage, which tells you what can be safely deprecated.
What to measure
| Signal | Why | Tooling |
|---|---|---|
| Operation-level RED metrics | Which client operations are slow/failing | Prometheus/OTel by operationName |
| Field resolver timing | Find slow fields/N+1 | Apollo tracing, Hive, OTel |
| Field usage stats | Safe deprecation decisions | Schema registry |
| Error codes | Classify failures | extensions.code in logs/metrics |
# OpenTelemetry span names (graphql semantic conventions)
graphql.parse
graphql.validate
query ProductPage (graphql.operation.name=ProductPage, graphql.operation.type=query)
└─ resolve Product.reviews (sampled)
Common pitfalls
- Anonymous operations polluting metrics.
- Tracing every field at 100% sampling.
- Ignoring partial errors because HTTP status is 200.
Key points
- Metrics by operation name
- Field-level timing and usage
- Errors with codes
Further reading: OpenTelemetry: GraphQL semantic conventions
Practice questions
Why are standard HTTP dashboards misleading for GraphQL?
Answer
All traffic hits one endpoint and usually returns 200 even with errors, so latency/error rates must be broken down by operation name and errors[] contents.
How does field usage data help schema evolution?
Answer
It shows which clients still request deprecated fields, so you know when removal is safe and whom to contact.
Open in the app to mark lessons complete, take notes and track your progress.