Master Graphql
Battle-tested skill for graphql, gives, clients, exactly. Includes structured workflows, validation checks, and reusable patterns for development.
GraphQL API Development Skill
A Claude Code skill for building production-grade GraphQL APIs — covering schema design, resolver patterns, N+1 query prevention with DataLoader, authentication, pagination, and performance optimization.
When to Use This Skill
Choose this skill when:
- Designing a GraphQL schema for a new API
- Implementing resolvers with proper error handling and authentication
- Solving N+1 query performance problems with DataLoader
- Adding pagination, filtering, and sorting to GraphQL queries
- Migrating from REST to GraphQL or adding a GraphQL layer
- Setting up GraphQL subscriptions for real-time data
Consider alternatives when:
- You need a simple CRUD API (REST may be simpler)
- You need file uploads as the primary use case (use REST or tus)
- You need high-throughput streaming (use gRPC)
Quick Start
# Install dependencies npm install @apollo/server graphql dataloader # Set up Apollo Server claude "create a GraphQL API with users and posts"
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; const typeDefs = `#graphql type User { id: ID! name: String! email: String! posts: [Post!]! } type Post { id: ID! title: String! content: String! author: User! } type Query { user(id: ID!): User users(limit: Int, offset: Int): [User!]! post(id: ID!): Post } type Mutation { createPost(title: String!, content: String!): Post! } `; const resolvers = { Query: { user: (_, { id }) => userService.findById(id), users: (_, { limit, offset }) => userService.findAll({ limit, offset }), }, User: { posts: (parent, _, { loaders }) => loaders.postsByUser.load(parent.id), }, };
Core Concepts
Schema Design Patterns
| Pattern | Use Case | Example |
|---|---|---|
| Connection Pagination | Large lists with cursor-based pagination | usersConnection(first: 10, after: "cursor") |
| Input Types | Complex mutation arguments | createUser(input: CreateUserInput!) |
| Union Types | Polymorphic results | SearchResult = User | Post | Comment |
| Interfaces | Shared fields across types | interface Node { id: ID! } |
| Enums | Constrained value sets | enum Role { ADMIN, USER, GUEST } |
DataLoader for N+1 Prevention
import DataLoader from 'dataloader'; // Without DataLoader: N+1 queries // Query 10 users → 10 separate queries for each user's posts // With DataLoader: 2 queries total function createLoaders() { return { postsByUser: new DataLoader(async (userIds: string[]) => { const posts = await db.posts.findMany({ where: { authorId: { in: userIds } } }); // Map results back to input order return userIds.map(id => posts.filter(p => p.authorId === id)); }), }; }
Cursor-Based Pagination
const typeDefs = `#graphql type UserConnection { edges: [UserEdge!]! pageInfo: PageInfo! totalCount: Int! } type UserEdge { cursor: String! node: User! } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String } type Query { users(first: Int, after: String, last: Int, before: String): UserConnection! } `;
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
server | string | "apollo" | GraphQL server: apollo, mercurius, yoga |
schema_approach | string | "schema-first" | Schema: schema-first, code-first |
pagination | string | "cursor" | Pagination: cursor (Relay), offset, none |
depth_limit | number | 10 | Maximum query nesting depth |
complexity_limit | number | 1000 | Maximum query complexity score |
introspection | boolean | true | Enable schema introspection (disable in prod) |
playground | boolean | true | Enable GraphQL playground UI |
tracing | boolean | false | Enable Apollo tracing for performance |
Best Practices
-
Use DataLoader for every relationship resolver — any resolver that loads related data should use DataLoader to batch and cache database queries within a single request; this eliminates N+1 queries.
-
Implement query depth and complexity limits — without limits, a malicious client can craft deeply nested queries that overload your server; set
depth_limit: 10andcomplexity_limit: 1000. -
Use cursor-based pagination for production APIs — offset pagination breaks when data changes between pages; cursor pagination is stable and performs better on large datasets.
-
Disable introspection in production — schema introspection exposes your entire API surface; disable it in production and use a schema registry or documentation site instead.
-
Return structured errors with error codes — use GraphQL's error extensions to include machine-readable error codes alongside human-readable messages so clients can handle errors programmatically.
Common Issues
N+1 query problem causes slow responses — Each relationship resolver fires a separate database query. Implement DataLoader for batching and caching. Profile with Apollo tracing to identify which resolvers are the bottleneck.
Clients request too much data in one query — Without limits, clients can request the entire graph in one call. Implement query complexity analysis that assigns cost to each field and rejects queries exceeding the budget.
Schema evolution breaks existing clients — Removing or renaming fields breaks clients. Use @deprecated(reason: "Use newField") to mark fields for removal, add new fields alongside old ones, and remove deprecated fields only after all clients have migrated.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.