N+1 resolver problem
Nested GraphQL queries trigger N+1 database calls — one per parent item. We implement DataLoader for all list resolvers, batching database calls to a single query per type per request.
GraphQL Apollo Federation Subscriptions
GraphQL eliminates over-fetching and under-fetching by letting clients request exactly the data they need — reducing API round trips, payload size and frontend complexity. We design GraphQL schemas, optimise resolver performance (DataLoader, query depth limiting), implement real-time subscriptions and build federated GraphQL gateways for US and EU clients on Node.js, Python and Java backends.
GraphQL eliminates over-fetching and under-fetching by letting clients request exactly the data they need — reducing API round trips, payload size and frontend complexity. We design GraphQL schemas, optimise resolver performance (DataLoader, query depth limiting), implement real-time subscriptions and build federated GraphQL gateways for US and EU clients on Node.js, Python and Java backends.
Challenges
Nested GraphQL queries trigger N+1 database calls — one per parent item. We implement DataLoader for all list resolvers, batching database calls to a single query per type per request.
Introspection enabled in production exposes the full data model to attackers. We disable introspection in production, add query depth limiting (max 7 levels) and query complexity analysis (max score 1000).
GraphQL schemas are versionless — deprecating fields requires coordinating with all clients. We use @deprecated directives, monitor deprecated field usage in Apollo Studio and maintain a field-removal timeline agreed with client teams.
Apollo Federation supergraphs with 10+ subgraphs introduce distributed tracing challenges and schema composition failures. We structure subgraph boundaries by domain, test composition in CI and implement gateway-level distributed tracing.
WebSocket-based subscriptions are stateful — they don't scale horizontally without a pub/sub backend. We use Redis pub/sub as the subscription transport layer so any gateway instance can serve any subscription.
GDPR requires that EU PII is only returned to authorised callers. We implement resolver-level field directives (@auth, @redact) that check claims from the JWT context before returning PII fields — not at the HTTP layer.
Solutions
Domain-driven schema design with relay-style pagination, connection types and input validation — built for long-term evolution without breaking clients.
Introspection disabled, query depth and complexity limits, persisted queries for production clients, JWT context validation and field-level @auth directives.
DataLoader batching for all N+1 resolver patterns, Redis query caching for expensive resolvers, and query complexity analysis to identify expensive operations before they reach production.
Federated supergraph from multiple subgraphs — entity references, @key directives, subgraph composition testing in CI and gateway-level distributed tracing.
WebSocket subscriptions with Redis pub/sub backend — horizontally scalable, with automatic reconnection and subscription deduplication on the client.
Incremental migration strategy: GraphQL gateway wraps existing REST endpoints via RESTDataSource, gradually replaced by native resolvers as the backend migrates.
Stack
GraphQL, Apollo Server 4, Apollo Federation 2, DataLoader, GraphQL Yoga, Strawberry (Python), Netflix DGS (Java), WebSockets (subscriptions), PostgreSQL, Redis, Sentry.
Compliance
GDPR-aligned · query depth limiting · field-level auth · PII masking in resolvers
Cases
Production social platform — App Store + Google Play, live across the US and EU — with geo Radar, encrypted messaging and a virtual economy.
Native iOS and Android e-signature clients with a Symfony + React CRM for a cross-border law firm — KYC onboarding and a defensible evidence trail for US & EU matters.
Cross-platform sports news app and web portal — Telegram-bot CMS instead of a custom admin, Markdown publishing pipeline.
Why YuSMP
We design the GraphQL schema as a product contract before writing resolvers — ensuring the API serves frontend needs, not backend convenience.
N+1 is the most common GraphQL production issue. We implement DataLoader for every list resolver on day one, not after the first performance incident.
Even single-graph projects are built with federation-compatible types — @key directives, entity resolvers — so adding a second subgraph later is additive, not breaking.
FAQ
GraphQL is the better choice when: multiple clients (web, iOS, Android, partners) consume the same API and have different data needs; the frontend team changes data requirements frequently; you need real-time subscriptions alongside queries; or you're building a product platform where third-party developers query your data. REST is the better choice for simple CRUD services, public APIs where HTTP caching is critical, or teams without GraphQL experience where the learning curve outweighs the benefits.
Apollo Federation 2 composes multiple subgraph schemas into a single supergraph. Each subgraph owns its domain types and exposes @key-decorated entities. The Apollo Router (or Apollo Gateway) routes incoming queries to the correct subgraphs, fetches entity references via the @external and @requires directives, and assembles the response. Schema composition is validated in CI — the router only starts if the composed supergraph is valid.
Query depth limiting (max 7 levels), query complexity analysis (max score 1000, calculated per field), rate limiting on the HTTP layer via Redis, persisted queries (production clients can only run pre-approved queries), and introspection disabled in production. For large-scale APIs, we add APQ (Automatic Persisted Queries) to reduce payload size and Apollo Studio anomaly detection for unusual query patterns.
GraphQL subscriptions are WebSocket connections — stateful. A single server instance can hold thousands of subscriptions, but horizontal scaling requires routing subscription events to the correct server. We use Redis pub/sub: when an event occurs, the publishing service writes to Redis; every gateway instance subscribes to Redis and forwards the event to the correct WebSocket connection. This scales to hundreds of thousands of concurrent subscriptions.
The GraphQL spec does not cover file uploads. We use the multipart request spec (graphql-multipart-request-spec) — either via Apollo Server's built-in upload support or graphql-upload middleware. Files are streamed directly to S3 from the resolver without touching the application server disk. Alternatively, we implement a REST upload endpoint alongside GraphQL for large or frequent file uploads.
Field-level access control via custom directives (@auth, @requiresRole) that check JWT claims before returning PII fields. Data-subject request resolvers that anonymise or return all data for a given user ID. Query audit logging — every query is logged with the authenticated user ID and resolved fields. For EU deployments, the GraphQL gateway routes EU-resident entity queries to EU-region resolvers that enforce data-residency.
We use Apollo Server's RESTDataSource to wrap existing REST endpoints in GraphQL resolvers. The GraphQL schema is designed first based on client data needs, then resolvers delegate to REST. As backend services are updated, resolvers migrate from REST calls to direct database queries. This allows frontend teams to adopt GraphQL immediately while backend migration happens incrementally over weeks or months.
Response within 1 business day. NDA on request.