home / skills / pluginagentmarketplace / custom-plugin-graphql / graphql-schema-design
npx playbooks add skill pluginagentmarketplace/custom-plugin-graphql --skill graphql-schema-designReview the files below or copy the command above to add this skill to your agents.
---
name: graphql-schema-design
description: Design production-grade GraphQL schemas with best practices and patterns
sasmp_version: "1.3.0"
bonded_agent: 02-graphql-schema
bond_type: PRIMARY_BOND
version: "2.0.0"
complexity: intermediate
estimated_time: "3-5 hours"
prerequisites: ["graphql-fundamentals"]
---
# GraphQL Schema Design Skill
> Architect scalable, maintainable GraphQL APIs
## Overview
Learn industry-standard patterns for designing GraphQL schemas that scale. Covers naming conventions, pagination, error handling, and schema evolution.
---
## Quick Reference
| Pattern | When to Use | Example |
|---------|-------------|---------|
| Connection | Paginated lists | `users: UserConnection!` |
| Payload | Mutation results | `CreateUserPayload` |
| Input | Mutation args | `CreateUserInput` |
| Interface | Shared fields | `interface Node { id: ID! }` |
| Union | Multiple types | `SearchResult = User \| Post` |
---
## Core Patterns
### 1. Naming Conventions
```graphql
# Types: PascalCase
type User { }
type UserProfile { }
# Fields: camelCase
type User {
firstName: String!
lastName: String!
createdAt: DateTime!
isActive: Boolean! # Boolean prefix: is, has, can
}
# Queries: noun (singular/plural)
type Query {
user(id: ID!): User # Singular
users: UserConnection! # Plural
}
# Mutations: verb + noun
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
deleteUser(id: ID!): DeleteUserPayload!
# Actions
sendEmail(input: SendEmailInput!): SendEmailPayload!
publishPost(id: ID!): PublishPostPayload!
}
# Inputs: [Action][Type]Input
input CreateUserInput { }
input UpdateUserInput { }
input UserFilterInput { }
# Payloads: [Action][Type]Payload
type CreateUserPayload { }
type UpdateUserPayload { }
```
### 2. Relay-Style Pagination
```graphql
# Connection pattern
type Query {
users(
first: Int
after: String
last: Int
before: String
filter: UserFilter
): UserConnection!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
# Usage
query GetUsers {
users(first: 10, after: "cursor123") {
edges {
node { id name }
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
```
### 3. Error Handling
```graphql
# Payload pattern (recommended)
type CreateUserPayload {
user: User
errors: [UserError!]!
}
type UserError {
field: String
message: String!
code: UserErrorCode!
}
enum UserErrorCode {
INVALID_EMAIL
DUPLICATE_EMAIL
WEAK_PASSWORD
NOT_FOUND
UNAUTHORIZED
}
# Union pattern (type-safe)
union CreateUserResult =
| CreateUserSuccess
| ValidationError
| NotAuthorizedError
type CreateUserSuccess {
user: User!
}
type ValidationError {
field: String!
message: String!
}
type NotAuthorizedError {
message: String!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserResult!
}
```
### 4. Node Interface
```graphql
# Global object identification
interface Node {
id: ID!
}
type Query {
node(id: ID!): Node
nodes(ids: [ID!]!): [Node]!
}
type User implements Node {
id: ID!
name: String!
}
type Post implements Node {
id: ID!
title: String!
}
# Enables refetching any object by ID
query RefetchUser {
node(id: "User:123") {
... on User {
name
email
}
}
}
```
### 5. Schema Organization
```graphql
# schema.graphql (root)
type Query {
# User domain
user(id: ID!): User
users(filter: UserFilter): UserConnection!
# Product domain
product(id: ID!): Product
products(filter: ProductFilter): ProductConnection!
}
type Mutation {
# User mutations
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
# Product mutations
createProduct(input: CreateProductInput!): CreateProductPayload!
}
# types/user.graphql
type User implements Node {
id: ID!
email: String!
name: String!
createdAt: DateTime!
orders: OrderConnection!
}
# types/product.graphql
type Product implements Node {
id: ID!
name: String!
price: Money!
inventory: Int!
}
```
---
## Design Decisions
### When to Use What
```
Returning a list?
├── Small fixed size (<20) → [Item!]!
└── Variable/large size → ItemConnection!
Mutation result?
├── Can have user errors → Payload pattern
└── System errors only → Direct return
Multiple possible types?
├── Completely different → Union
└── Share common fields → Interface
Nested data?
├── Always needed together → Embed
└── Sometimes needed → Separate + ID reference
```
### Nullability Strategy
```graphql
type User {
# Always required
id: ID!
email: String!
# Optional (user choice)
nickname: String
bio: String
# Lists: require list, require items
posts: [Post!]! # Never null, items never null
# Computed (may fail)
avatar: String # Nullable if generation can fail
}
```
---
## Troubleshooting
| Issue | Cause | Solution |
|-------|-------|----------|
| Breaking change | Removed field | Use @deprecated first |
| Over-fetching | No pagination | Add Connection pattern |
| N+1 queries | Direct relations | Use DataLoader |
| Type explosion | Too many types | Use interfaces/generics |
### Schema Health Check
```bash
# Validate
npx graphql-inspector validate schema.graphql
# Check breaking changes
npx graphql-inspector diff old.graphql new.graphql
# Coverage analysis
npx graphql-inspector coverage schema.graphql queries/*.graphql
```
---
## Usage
```
Skill("graphql-schema-design")
```
## Related Skills
- `graphql-fundamentals` - Basic types and syntax
- `graphql-resolvers` - Implementing the schema
- `graphql-security` - Auth-aware design
## Related Agent
- `02-graphql-schema` - For detailed guidance