skills/graphql-server-architect/SKILL.md
DataLoader, subscriptions, federation, and schema stitching for GraphQL APIs. Activate on: GraphQL, DataLoader, subscription, federation, schema stitching, resolver, SDL, Apollo, Yoga. NOT for: REST API design (use api-architect), frontend GraphQL clients (use relevant frontend skill).
npx skillsauth add curiositech/windags-skills graphql-server-architectInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Design production-grade GraphQL APIs with efficient data loading, real-time subscriptions, and federated schema architecture.
Activate on: "GraphQL", "DataLoader", "subscription", "federation", "schema stitching", "resolver", "SDL", "Apollo Server", "GraphQL Yoga", "Pothos", "query complexity"
NOT for: REST API design → api-architect | Frontend GraphQL client → relevant frontend skill | Database queries → data-warehouse-optimizer
| Domain | Technologies | |--------|-------------| | Servers | GraphQL Yoga 5.x, Apollo Server 4.x, Mercurius 14+ | | Schema | Pothos (code-first), SDL (schema-first), GraphQL Codegen | | Federation | Apollo Federation 2.8+, GraphQL Mesh, Schema Stitching | | Performance | DataLoader, @defer/@stream, persisted queries, query complexity | | Real-Time | GraphQL Subscriptions (WebSocket), graphql-ws, SSE transport |
import DataLoader from 'dataloader';
// Create per-request DataLoader
function createLoaders() {
return {
userById: new DataLoader<string, User>(async (ids) => {
// Single batch query instead of N queries
const users = await db.query('SELECT * FROM users WHERE id = ANY($1)', [ids]);
const map = new Map(users.map(u => [u.id, u]));
return ids.map(id => map.get(id) ?? new Error(`User ${id} not found`));
}),
};
}
// Resolver uses loader — automatically batched
const resolvers = {
Post: {
author: (post, _, { loaders }) => loaders.userById.load(post.authorId),
},
};
Clients
↓
Apollo Router (supergraph)
├─→ Users Subgraph (owns User type)
├─→ Orders Subgraph (extends User with orders)
└─→ Products Subgraph (owns Product type)
Each subgraph is an independent GraphQL service.
Router composes query plans across subgraphs.
# Users subgraph
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
# Orders subgraph — extends User from Users subgraph
type User @key(fields: "id") {
id: ID!
orders: [Order!]!
}
type Order {
id: ID!
total: Float!
status: OrderStatus!
}
import { createComplexityLimitRule } from 'graphql-validation-complexity';
const complexityLimit = createComplexityLimitRule(1000, {
scalarCost: 1,
objectCost: 10,
listFactor: 20,
onCost: (cost) => {
if (cost > 800) logger.warn(`High complexity query: ${cost}`);
},
});
const server = createYoga({
schema,
validationRules: [complexityLimit],
});
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.