GraphQL API Monitoring: The Complete Guide for Production Teams
๐ก Monitor your APIs โ know when they go down before your users do
Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.
Affiliate link โ we may earn a commission at no extra cost to you
GraphQL API Monitoring: The Complete Guide for Production Teams
Quick Answer: GraphQL API monitoring requires a fundamentally different approach than REST API monitoring. You can't just check HTTP status codes โ you need to track query complexity, resolver performance, error rates within 200 responses, and the N+1 query problem. This guide covers everything you need to monitor GraphQL APIs in production.
GraphQL has transformed how teams build APIs. The flexibility that makes it powerful for frontend developers โ nested queries, field selection, real-time subscriptions โ creates unique monitoring blind spots that traditional API monitoring tools miss entirely.
If you're running GraphQL in production and only checking whether your /graphql endpoint returns 200, you're flying blind.
|---|---| | Partial failures | Entire endpoint fails | Some fields resolve, others error โ response still 200 | | Query complexity attacks | N/A (endpoints are fixed) | Malicious deeply nested queries consume server resources | | N+1 query explosions | Controllable per endpoint | Resolver composition can trigger thousands of DB queries | | Schema drift | Versioned endpoints | Deprecation warnings buried in responses | | Subscription memory leaks | N/A | WebSocket connections accumulate without cleanup |
The 7 Essential GraphQL Metrics to Track
1. Query Execution Time (by Operation)
Don't measure average response time for your /graphql endpoint โ that's meaningless. Instead, track execution time per named operation.
# This is operation "GetUserProfile"
query GetUserProfile($id: ID!) {
user(id: $id) {
name
email
avatar
}
}
What to track:
- P50, P95, and P99 latency per operation name
- Latency trend over time (regression detection)
- Unnamed/anonymous queries (these are your monitoring blind spot)
Pro tip: Require operation names in production. Reject anonymous queries. You can't monitor what you can't name.
2. Resolver-Level Performance
The real performance story in GraphQL happens at the resolver level. A query might be fast overall, but one resolver could be doing something catastrophically expensive that's masked by caching elsewhere.
Track for each resolver:
- Execution time โ How long does this resolver take?
- Call count โ How many times is it invoked per request? (Watch for N+1)
- Error rate โ Which resolvers fail most often?
- Database queries triggered โ Is one resolver spawning 100 SQL queries?
3. Error Rate (Within 200 Responses)
This is the metric REST-focused tools miss entirely. A GraphQL response with HTTP 200 can contain:
{
"data": {
"user": {
"name": "Jane",
"orders": null
}
},
"errors": [
{
"message": "Failed to fetch orders: connection timeout",
"path": ["user", "orders"],
"extensions": {
"code": "DOWNSTREAM_ERROR"
}
}
]
}
The user got their name but not their orders. Your HTTP monitoring says "200 OK, all good." Your users say "the app is broken."
Track these error metrics:
- Percentage of responses containing
errorsarray - Error count by error code/classification
- Error count by field path (which resolvers fail?)
- Partial success vs. complete failure ratio
4. Query Complexity Score
GraphQL lets clients construct arbitrarily complex queries. Without limits, a single query can bring down your server:
# A "query of doom" โ exponential resolver calls
query Evil {
users(first: 100) {
friends(first: 100) {
friends(first: 100) {
friends(first: 100) {
name
}
}
}
}
}
This innocent-looking query could trigger 100 ร 100 ร 100 ร 100 = 100 million resolver calls.
Implement and monitor:
- Query depth limiting โ Reject queries deeper than N levels (typically 7-10)
- Query complexity scoring โ Assign cost values to fields and reject queries above a threshold
- Breadth limiting โ Cap the number of items at each pagination level
Track the distribution of complexity scores across your traffic. Rising averages may indicate abuse or poorly optimized client queries.
5. Subscription Health
GraphQL subscriptions maintain persistent WebSocket connections. Unlike request/response queries, subscriptions can silently degrade:
- Active subscription count โ How many WebSocket connections are open?
- Subscription duration โ Are connections being properly cleaned up?
- Message delivery rate โ Are subscribers actually receiving updates?
- Memory per subscription โ Watch for leaks as connections accumulate
A common failure: subscription connections pile up after client disconnects aren't properly handled. Memory usage grows linearly until the server OOMs.
6. Schema Usage Analytics
Your schema evolves over time. Fields get deprecated, new types get added. Monitoring schema usage tells you:
- Which fields are actually used โ Safe to deprecate unused ones
- Deprecated field usage โ Are clients still hitting deprecated fields?
- New field adoption โ Is the feature you launched actually being queried?
- Type coverage โ Are entire types going unused?
This isn't just operational monitoring โ it's product intelligence. If nobody queries the user.preferences field you spent two sprints building, that's valuable information.
7. Cache Hit Rate
GraphQL caching is more complex than REST caching because query shapes are dynamic. Monitor:
- Response cache hit rate โ For persisted/allowlisted queries
- DataLoader cache hit rate โ Per-request batching effectiveness
- CDN/edge cache rate โ If using
@cacheControldirectives - Normalized cache effectiveness โ For client-side caches (Apollo, urql)
A dropping cache hit rate often signals a client update that changed query shapes, breaking your caching strategy.
Monitoring the N+1 Problem in Production
The N+1 query problem is GraphQL's most notorious performance trap. It happens when a resolver for a list of items triggers a separate database query for each item's related data.
Example:
query {
posts(first: 50) { # 1 query to fetch 50 posts
title
author { # 50 individual queries to fetch each author
name
}
}
}
Result: 1 + 50 = 51 database queries for a single GraphQL request.
How to Detect N+1 in Production
- Track database query count per GraphQL operation. If a query generates more than 10-20 SQL queries, flag it.
- Monitor resolver call counts. If
Author.resolveis called 50 times in one request, you likely have an N+1. - Compare resolver call count vs. DataLoader batch count. If you're using DataLoader correctly, 50 resolver calls should produce 1 batched database query.
- Set alerts on query count thresholds. A sudden spike from 5 to 500 DB queries per request means something changed.
The DataLoader Solution (and Monitoring It)
DataLoader batches and caches resolver calls within a single request. Monitor its effectiveness:
Metric: dataloader.batch_size
- Average: 25 (good โ batching is working)
- Average: 1.1 (bad โ DataLoader is loaded but not actually batching)
Metric: dataloader.cache_hit_rate
- 80%+ (good โ deduplication is effective)
- <10% (bad โ cache isn't helping, investigate key generation)
Setting Up GraphQL-Aware Alerts
Standard API alerting rules don't work for GraphQL. Here's how to set up alerts that actually catch problems:
Alert Rules That Matter
| Alert | Threshold | Why |
|---|---|---|
| Error rate in responses | >5% of responses contain errors |
Catches partial failures invisible to HTTP monitoring |
| Operation P95 latency | >2x baseline for any named operation | Detects resolver regressions |
| Query complexity rejection rate | >10% of queries rejected | Clients may be constructing expensive queries |
| Resolver error spike | >3x normal for any single resolver | Isolates downstream dependency failures |
| Active subscriptions | >2x normal count | WebSocket connection leak |
| DB queries per operation | >50 queries in single operation | N+1 problem emerged |
Avoiding Alert Fatigue
GraphQL's partial failure model means you'll see errors constantly in production โ some of them are expected and harmless. Reduce noise by:
- Classifying errors by severity. A deprecated field warning โ a database timeout.
- Alerting on rate changes, not absolute counts. 10 errors/minute might be normal. 100 errors/minute after being at 10 is a problem.
- Grouping alerts by operation name. Don't send 50 alerts when one resolver breaks โ group them.
For setting up effective alerting workflows, see our guide on API monitoring best practices and how to set up API outage notifications.
Best Tools for GraphQL API Monitoring
Apollo Studio (Apollo GraphOS)
The most GraphQL-native monitoring solution. If you're using Apollo Server, this is the natural choice.
Strengths:
- Per-operation performance tracking out of the box
- Field-level usage analytics
- Schema change tracking and breaking change detection
- Client awareness (which app version sends which queries)
Limitations:
- Tightly coupled to Apollo ecosystem
- Pricing scales with operation volume
Grafana + Prometheus + Custom Metrics
The open-source approach. Instrument your GraphQL server with custom Prometheus metrics and visualize in Grafana.
Best for: Teams that want full control and already run Prometheus/Grafana.
What to instrument:
graphql_operation_duration_seconds(histogram, labeled by operation name)graphql_resolver_duration_seconds(histogram, labeled by resolver)graphql_errors_total(counter, labeled by error code)graphql_query_complexity(histogram)
Datadog APM
Solid general-purpose APM that supports GraphQL through its tracing libraries. Parses operation names from queries and tracks resolver-level spans.
Best for: Teams already using Datadog who want GraphQL visibility without adding another tool.
External Synthetic Monitoring
All the tools above monitor from inside your infrastructure. You also need external monitoring โ checking your GraphQL API from the outside, the way your users experience it.
This is where tools like API Status Check come in. Configure synthetic GraphQL queries that run on a schedule, measuring availability and response time from multiple geographic locations. When your endpoint goes down or response times spike, you'll know before your users report it.
For a comparison of monitoring approaches, check out our API monitoring tools comparison.
GraphQL Monitoring Checklist
Use this checklist to audit your current GraphQL monitoring setup:
Query-Level Monitoring:
- Track latency per named operation (P50/P95/P99)
- Require operation names โ reject anonymous queries in production
- Monitor query complexity scores and rejection rates
- Alert on latency regressions per operation
Resolver-Level Monitoring:
- Track resolver execution time and call counts
- Monitor DataLoader batch sizes and cache hit rates
- Alert on N+1 patterns (DB query count per request)
- Track resolver error rates independently
Error Monitoring:
- Parse and classify errors from response bodies (not just HTTP status)
- Track partial failure rates
- Monitor deprecated field usage
- Alert on error rate spikes by category
Infrastructure Monitoring:
- Track active WebSocket connections (subscriptions)
- Monitor memory usage correlated with subscription count
- Set up external synthetic monitoring for uptime
- Track schema registry changes and breaking changes
Operational Hygiene:
- Maintain a persisted query allowlist for production
- Log and review rejected queries (complexity/depth violations)
- Run regular schema usage audits
- Document your monitoring runbook for GraphQL-specific incidents
๐ก GraphQL monitoring needs tools that understand operations, not just endpoints. Better Stack monitors your GraphQL endpoint availability and response times from 6 continents โ catch when your
/graphqlgoes down or latency spikes before users hit slow queries.
Conclusion
GraphQL monitoring isn't harder than REST monitoring โ it's just different. The flexibility that makes GraphQL powerful for developers creates unique observability challenges that generic HTTP monitoring tools can't address.
The key principles:
- Monitor operations, not endpoints. Your
/graphqlendpoint is a multiplexer, not a resource. - Look inside 200 responses. GraphQL errors hide in response bodies.
- Track resolver performance individually. The query is the symptom; the resolver is the cause.
- Guard against complexity. Depth limiting and complexity scoring aren't optional in production.
- Watch for N+1. It's the most common performance killer in GraphQL, and it's invisible without proper instrumentation.
Start with operation-level latency tracking and error parsing. Then add resolver-level observability. Then layer on complexity analysis and schema usage analytics. You don't need everything on day one โ but you do need more than just "is the endpoint up?"
For a broader look at API monitoring fundamentals, check out our API monitoring best practices guide or explore how API Status Check can help you monitor your GraphQL endpoints alongside all your other API dependencies.
๐ Tools We Use & Recommend
Tested across our own infrastructure monitoring 200+ APIs daily
Uptime Monitoring & Incident Management
Used by 100,000+ websites
Monitors your APIs every 30 seconds. Instant alerts via Slack, email, SMS, and phone calls when something goes down.
โWe use Better Stack to monitor every API on this site. It caught 23 outages last month before users reported them.โ
Secrets Management & Developer Security
Trusted by 150,000+ businesses
Manage API keys, database passwords, and service tokens with CLI integration and automatic rotation.
โAfter covering dozens of outages caused by leaked credentials, we recommend every team use a secrets manager.โ
SEO & Site Performance Monitoring
Used by 10M+ marketers
Track your site health, uptime, search rankings, and competitor movements from one dashboard.
โWe use SEMrush to track how our API status pages rank and catch site health issues early.โ
Alert Pro
14-day free trialStop checking โ get alerted instantly
Next time your critical APIs goes down, you'll know in under 60 seconds โ not when your users start complaining.
- Email alerts for your critical APIs + 9 more APIs
- $0 due today for trial
- Cancel anytime โ $9/mo after trial