graphql-schema-design
Use when designing GraphQL schemas with type system, SDL patterns, field design, pagination, directives, and versioning strategies for maintainable and scalable APIs.
What this skill does
# GraphQL Schema Design
Apply GraphQL schema design principles to create well-structured,
maintainable, and scalable GraphQL APIs. This skill covers the type
system, Schema Definition Language (SDL), field design patterns,
pagination strategies, directives, and schema evolution techniques.
## Core Type System
### Object Types
Object types are the fundamental building blocks of GraphQL schemas.
Each object type represents a kind of object you can fetch from your
service, and what fields it has.
```graphql
type User {
id: ID!
username: String!
email: String!
createdAt: DateTime!
posts: [Post!]!
profile: Profile
}
type Post {
id: ID!
title: String!
content: String!
author: User!
publishedAt: DateTime
tags: [String!]!
}
```
### Interface Types
Interfaces define abstract types that multiple object types can
implement. Use interfaces when multiple types share common fields.
```graphql
interface Node {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
}
interface Timestamped {
createdAt: DateTime!
updatedAt: DateTime!
}
type Article implements Node & Timestamped {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
title: String!
content: String!
author: User!
}
type Comment implements Node & Timestamped {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
text: String!
author: User!
post: Post!
}
```
### Union Types
Union types represent values that could be one of several object types.
Use unions when a field can return different types without shared
fields.
```graphql
union SearchResult = Article | User | Tag | Comment
type Query {
search(query: String!): [SearchResult!]!
}
# Query example
query {
search(query: "graphql") {
__typename
... on Article {
title
content
}
... on User {
username
email
}
... on Tag {
name
count
}
}
}
```
### Enum Types
Enums define a specific set of allowed values for a field. Use enums
for fields with a fixed set of options to ensure type safety.
```graphql
enum UserRole {
ADMIN
MODERATOR
USER
GUEST
}
enum PostStatus {
DRAFT
PUBLISHED
ARCHIVED
DELETED
}
enum SortOrder {
ASC
DESC
}
type User {
id: ID!
role: UserRole!
status: AccountStatus!
}
enum AccountStatus {
ACTIVE
SUSPENDED
DEACTIVATED
}
```
### Input Types
Input types are used for complex arguments in queries and mutations.
They allow you to pass structured data as a single argument.
```graphql
input CreateUserInput {
username: String!
email: String!
password: String!
profile: UserProfileInput
}
input UserProfileInput {
firstName: String
lastName: String
bio: String
avatarUrl: String
}
input UpdatePostInput {
title: String
content: String
status: PostStatus
tags: [String!]
}
input PostFilterInput {
status: PostStatus
authorId: ID
tags: [String!]
createdAfter: DateTime
createdBefore: DateTime
}
type Mutation {
createUser(input: CreateUserInput!): User!
updatePost(id: ID!, input: UpdatePostInput!): Post!
}
type Query {
posts(filter: PostFilterInput, limit: Int): [Post!]!
}
```
## Custom Scalars
Custom scalars extend the built-in scalar types (String, Int, Float,
Boolean, ID) with domain-specific types.
```graphql
scalar DateTime
scalar EmailAddress
scalar URL
scalar JSON
scalar UUID
scalar PositiveInt
scalar Currency
type User {
id: UUID!
email: EmailAddress!
website: URL
createdAt: DateTime!
metadata: JSON
age: PositiveInt
}
type Product {
id: ID!
price: Currency!
images: [URL!]!
}
```
## Directives
Directives provide a way to modify execution behavior or add metadata
to your schema.
```graphql
# Built-in directives
type Query {
# Skip field if condition is true
user(id: ID!): User @skip(if: $skipUser)
# Include field only if condition is true
posts: [Post!]! @include(if: $includePosts)
}
type Post {
id: ID!
title: String!
# Mark field as deprecated with migration hint
oldTitle: String @deprecated(reason: "Use 'title' instead")
}
# Custom directives
directive @auth(requires: UserRole!) on FIELD_DEFINITION
directive @rateLimit(max: Int!, window: Int!) on FIELD_DEFINITION
directive @cacheControl(
maxAge: Int!
scope: CacheScope = PUBLIC
) on FIELD_DEFINITION | OBJECT
enum CacheScope {
PUBLIC
PRIVATE
}
type Query {
me: User @auth(requires: USER)
adminPanel: AdminData @auth(requires: ADMIN)
publicPosts: [Post!]!
@cacheControl(maxAge: 300)
@rateLimit(max: 100, window: 60)
}
```
## Nullable vs Non-Null Design
Carefully consider nullability in your schema design. Non-null fields
provide stronger guarantees but reduce flexibility.
```graphql
type User {
# Required fields - will never be null
id: ID!
username: String!
email: String!
# Optional fields - may be null
bio: String
website: URL
# Non-null list with nullable items
# List itself will never be null, but items can be
favoriteColors: [String]!
# Nullable list with non-null items
# List can be null, but if present, items won't be
phoneNumbers: [String!]
# Non-null list with non-null items
# Neither list nor items will be null
roles: [UserRole!]!
# Optional relationship
profile: Profile
# Required relationship
account: Account!
}
```
## Pagination Patterns
### Offset-Based Pagination
Simple pagination using limit and offset. Easy to implement but has
performance issues with large offsets.
```graphql
type Query {
posts(limit: Int = 10, offset: Int = 0): PostsResult!
}
type PostsResult {
posts: [Post!]!
total: Int!
hasMore: Boolean!
}
# Query example
query {
posts(limit: 20, offset: 40) {
posts {
id
title
}
total
hasMore
}
}
```
### Cursor-Based Pagination (Connections)
More efficient for large datasets and supports bidirectional
pagination. Based on Relay Connection specification.
```graphql
type Query {
posts(
first: Int
after: String
last: Int
before: String
): PostConnection!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type PostEdge {
node: Post!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
# Query example
query {
posts(first: 10, after: "Y3Vyc29yOjEw") {
edges {
cursor
node {
id
title
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
```
## Mutation Design Patterns
### Input Object Pattern
Use input objects for mutations to allow for easier evolution and
better organization of arguments.
```graphql
type Mutation {
createPost(input: CreatePostInput!): CreatePostPayload!
updatePost(input: UpdatePostInput!): UpdatePostPayload!
deletePost(input: DeletePostInput!): DeletePostPayload!
}
input CreatePostInput {
title: String!
content: String!
authorId: ID!
tags: [String!]
publishedAt: DateTime
}
type CreatePostPayload {
post: Post
errors: [UserError!]
success: Boolean!
}
type UserError {
message: String!
field: String
code: String!
}
input UpdatePostInput {
id: ID!
title: String
content: String
status: PostStatus
}
type UpdatePostPayload {
post: Post
errors: [UserError!]
success: Boolean!
}
```
## Error Handling in Schema
Design your schema to support both field-level and mutation-level
error handling.
```graphql
type Mutation {
# Option 1: Union return type
login(email: String!, password: String!): LoginResult!
}
union LoginResult = LoginSuccess | LoginError
type LoginSuccess {
user: User!
token: String!
expiresAt: DateTime!
}
type LoginError {
message: String!
code: LoginErrorCode!
}
enum LoginErrorCode {
INVALID_CREDENTIALS
ACCOUNT_LOCKED
EMAIL_NOT_VERIFIED
}
# Option 2: Payload with errors array
type Mutation {
updateUser(input: UpdateUserInput!): UpdateUserPayload!
}
type UpdateUserPayload {
user: User
errors: [UserError!]
success: BoolRelated in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.