GraphQL Schema, Federation & Performance Design
Design and fix GraphQL schemas, DataLoader resolvers, federation, and subscriptions without N+1 or breaking changes.
Before & after
Same prompt, same agent — the only difference is the skill.
Slow nested GraphQL queries usually point to the N+1 problem. When you query a list of items and each one resolves a nested field, you end up making one database query per item. Some solutions to consider: - Use DataLoader to batch and cache database calls within a request - Implement query depth limiting to prevent deeply nested queries - Add pagination to list fields - Consider query complexity analysis to reject expensive queries - Look into caching at the resolver level DataLoader is probably the most impactful change. It batches individual loads that occur within a single tick of the event loop. Would you like help implementing any of these?
That's N+1. Here's the fix in the order that matters.
THE SHAPE OF THE PROBLEM
query { posts(first: 50) { author { name } } }
→ 1 query for posts, then 50 for authors. 51 round trips for 50 rows.
1 — DATALOADER (does ~90% of the work)
loaders/userLoader.js
new DataLoader(async (ids) => {
const rows = await db.user.findMany({ where: { id: { in: ids } } })
const byId = new Map(rows.map(r => [r.id, r]))
return ids.map(id => byId.get(id) ?? null) // MUST return in input order
})
Two rules people get wrong:
• Construct per request, in context — a module-level loader caches across
users and leaks data between them.
• The batch fn must return results positionally, same length as keys.
Returning the raw DB rows silently mismatches when a row is missing.
51 queries → 2.
2 — DEPTH LIMIT — stop the pathological query, don't just make it fast
depthLimit(7) in validationRules. A client can nest
author→posts→author→posts forever; DataLoader makes that efficient, not
bounded.
3 — COMPLEXITY SCORING
Cost per field, reject over budget. first: 1000 on three nested
connections passes a depth limit and still melts the DB.
4 — CONNECTION PAGINATION on every list field
Unbounded lists are the thing depth limits can't save you from.
IF YOU'RE FEDERATED
Each subgraph needs its own loaders — the gateway batches entity
resolution across subgraphs, but not within one. A @key reference
resolver without a loader is the same N+1, one layer down.
Start with #1 and re-measure before doing the rest.About this skill
Your GraphQL endpoint started fast and now a single orders query fires 400 database calls, one failing field blanks the whole response, and nobody knows if removing a field will break the mobile app. This skill designs and repairs GraphQL APIs the way a practitioner who has run them in production would, with concrete SDL, resolver code, and migration steps.
What it does
- Designs schemas around client use cases: action-named mutations, input/payload types with typed user errors, and nullability chosen deliberately so one downstream failure does not null out an entire query
- Finds and kills N+1 patterns with per-request DataLoaders, including the hard cases: one-to-many relations, paginated children per parent, and composite keys
- Plans Apollo Federation 2 subgraph boundaries, @key entities, batched reference resolvers, @requires/@shareable/@override usage, and safe field migration between subgraphs
- Adds production guardrails: cost and depth limits that account for list multipliers, trusted documents, alias and batching abuse limits, and error masking
- Designs subscriptions with the right transport, a multi-instance pub/sub backend, per-event authorization, and reconnect behavior
- Classifies proposed schema changes as safe, dangerous, or breaking, and writes the deprecation-to-removal path
What you get
A right-sized answer: for a quick question, a direct fix; for a design or review, SDL, resolver and loader code, a ranked risk list, and an ordered rollout plan with assumptions stated up front.
Best for
Backend and full-stack engineers building or maintaining GraphQL APIs on Apollo Server, Apollo Router, or similar stacks, especially teams moving from a monolithic graph to federation or fighting performance problems under load.
SKILL.md preview
---
name: graphql-schema-federation-performance
description: Designs, reviews, and repairs GraphQL APIs - schema and nullability design, DataLoader batching for N+1, cursor pagination, Apollo Federation 2 subgraph boundaries, query cost limits, and subscriptions - delivering SDL, resolver code, and an ordered rollout plan. Use when the user says "design a GraphQL schema for...", "our GraphQL query times out under load", "my resolvers keep hitting the database hundreds of times", "split our graph into subgraphs with Apollo Federation", "add real-time subscriptions", "review this schema", "is removing this field a breaking change", or "one error wipes out the whole response".
---
… (sign up to view the full skill)More development skills
View all Development skills →Production Go: Concurrency, Services & Profiling
Production Go code with leak-free goroutines, context-correct services, wrapped errors, and pprof-driven performance fixes.
Backend Feature Build Plan
Builds one backend feature through gates: confirmed requirements, one-screen design, small tested slices, and a deploy/rollback handoff.
Consistent, Safe Application Logging
Adds structured, correlated logs with useful severity, safe fields, bounded volume, and targeted verification.
Reliable WebSocket Messaging and Scaling
Build WebSocket and Socket.IO systems with authorized rooms, reconnect recovery, bounded queues, and multi-node presence.