GraphQL API development skill. Schema design, resolver architecture, N+1 detection with DataLoader, subscriptions, federation, performance hardening. Triggers on: /godmode:graphql, "GraphQL schema", "fix N+1 queries", "set up subscriptions".
From godmodenpx claudepluginhub arbazkhan971/godmodeThis skill uses the workspace's default tool permissions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
/godmode:graphql# Detect GraphQL framework
grep -l "apollo-server\|graphql-yoga\|mercurius\|\
pothos\|nexus\|type-graphql\|strawberry\|gqlgen" \
package.json pyproject.toml go.mod 2>/dev/null
# Check for DataLoader usage
grep -rl "dataloader\|DataLoader" src/ 2>/dev/null
# Find schema files
find . -name "*.graphql" -o -name "*.gql" \
| head -10
GRAPHQL DISCOVERY:
Approach: SDL-first | Code-first
Framework: Apollo | Yoga | Mercurius | Pothos | gqlgen
Consumers: web app | mobile | third-party
Auth: JWT | session | API key
Federation: monolith | gateway + subgraphs
IF no DataLoader and has relations: N+1 is likely
IF no depth limit: production API is vulnerable
IF no complexity limit: one query can DoS the server
# SDL-first example
type Query {
user(id: ID!): User
users(first: Int!, after: String): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
# Every mutation returns payload with errors array
type CreateUserPayload {
user: User
errors: [UserError!]!
}
SCHEMA RULES:
Mutations return payload types (never throw)
All lists use Relay connections (edges, pageInfo)
Input types separate from output types
Non-nullable uses ! intentionally
Enums for fixed sets, never strings
THRESHOLDS:
Max query depth: 10 levels
Max query complexity: 1000 points
Connection max first/last: 100 items
IF depth > 10: reject query
IF complexity > 1000: reject query
Resolvers are thin orchestration — no business logic. Business logic lives in service layer.
N+1 DETECTION:
| Pattern | Action |
|-----------------------------|-----------------|
| List with nested relations | Add DataLoader |
| Field resolver with DB call | Must use loader |
| 3+ levels deep query | Audit batch plan|
DATALOADER RULES:
Every relation field MUST use DataLoader.
Create loaders per-request (not global).
Batch by ID, return in same order as input.
IF query count > N+1 for list of N: DataLoader missing
IF no DataLoader imports: flag all relation resolvers
SUBSCRIPTION ARCHITECTURE:
Transport: WebSocket (graphql-ws preferred)
Pub/Sub: Redis (production) | in-memory (dev)
THRESHOLDS:
Max subscription connections: 10K per server
Heartbeat interval: 30 seconds
IF > 1 server instance: must use Redis pub/sub
IF using in-memory pub/sub in prod: fix immediately
Each subgraph owns its entities. Gateway handles query planning. Subgraphs never call each other. Run composition checks before every merge.
REQUIRED DEFENSES:
Depth limit: 10 (configurable per operation)
Complexity limit: 1000 per query
Persisted queries or allowlist in production
Rate limiting: per-client, per-operation
FIELD COSTS:
Scalar field: 1 point
Object field: 2 points
List field: first * child_cost
Connection: first * (edge_cost + node_cost)
# Run schema validation
npx graphql-inspector validate schema.graphql
# Run N+1 regression tests
npx vitest run tests/graphql/ --reporter=verbose
TESTING LAYERS:
Schema validation: buildSchema succeeds
Resolver unit: mock context, test isolation
Integration: full query execution
N+1 regression: assert query count per operation
Contract: graphql-inspector diff (breaking changes)
GRAPHQL COMPLETE:
Types: <N> objects, <M> inputs, <K> enums
Operations: <N> queries, <M> mutations, <K> subs
DataLoaders: <N> (all relation fields covered)
Performance: depth <N>, complexity <N>
Commit: "graphql: <service> — <N> types, <M> operations, DataLoaders configured"
Never ask to continue. Loop autonomously until done.
1. Framework: apollo, yoga, mercurius, pothos, gqlgen
2. Approach: *.graphql = SDL, builder imports = code
3. DataLoader: scan for imports, flag if missing
4. Performance: depth-limit, complexity config
FOR each entity (leaf first):
1. Design types, connections, inputs, payloads
2. Implement resolvers (queries + mutations)
3. Create DataLoaders for all relation fields
4. Write tests (unit + integration + N+1 count)
5. IF N+1 detected: add DataLoader, re-test
6. IF breaking change: add new field, deprecate old
POST: Add complexity/depth limits, validate schema
Print: GraphQL: {types} types, {queries} queries, {mutations} mutations, {dataloaders} DataLoaders. N+1: {status}. Depth: {N}. Verdict: {verdict}.
timestamp types queries mutations dataloaders n1_fixed status
KEEP if: schema compiles AND zero N+1
AND mutations return payloads AND limits configured
DISCARD if: N+1 detected OR mutation throws
OR breaking change without version bump
STOP when ALL of:
- Schema compiles, snapshot test passes
- All relation fields have DataLoaders
- All mutations return payload types
- Depth + complexity limits configured
- No breaking changes vs previous schema