GraphQL Schema and API Design Guide

Design a well-structured, performant GraphQL schema with best practices for queries, mutations, subscriptions, and error handling.

Prompt Template

You are a senior API architect specializing in GraphQL. Help me design a production-ready GraphQL schema for the following application.

**Application:** [e.g., multi-tenant project management SaaS]
**Key entities:** [e.g., Users, Projects, Tasks, Comments, Teams]
**Auth model:** [e.g., JWT with role-based access — admin, member, viewer]
**Real-time needs:** [e.g., task status updates, new comments]
**Existing data sources:** [e.g., PostgreSQL, Redis cache, external REST APIs]

Deliver:
1. **Schema Design** — complete SDL with types, inputs, enums, interfaces, and unions where appropriate
2. **Query Design** — top-level queries with pagination (cursor-based), filtering, and sorting arguments
3. **Mutation Design** — mutations with proper input types, validation rules, and error union types
4. **Subscription Design** — real-time subscriptions for the specified use cases
5. **Relay Compliance** — Node interface, connection types, and global IDs if applicable
6. **N+1 Prevention** — DataLoader patterns and resolver optimization notes
7. **Auth Directives** — custom directives or middleware patterns for field-level authorization
8. **Error Handling** — structured error types vs GraphQL errors, when to use each
9. **Versioning Strategy** — how to evolve the schema without breaking clients
10. **Performance Considerations** — query complexity limits, depth limits, persisted queries

Include inline comments explaining design decisions and trade-offs.

Example Output

GraphQL Schema: Project Management SaaS

Core Types

interface Node {

id: ID!

}

type User implements Node {

id: ID!

email: String!

displayName: String!

role: UserRole!

teams: [Team!]!

createdAt: DateTime!

}

enum UserRole {

ADMIN

MEMBER

VIEWER

}

type Project implements Node {

id: ID!

name: String!

description: String

team: Team!

tasks(first: Int, after: String, filter: TaskFilter): TaskConnection!

createdAt: DateTime!

updatedAt: DateTime!

}

# Cursor-based pagination

type TaskConnection {

edges: [TaskEdge!]!

pageInfo: PageInfo!

totalCount: Int!

}

Mutations with Error Unions

union CreateProjectResult = CreateProjectSuccess | ValidationError | AuthorizationError

type CreateProjectSuccess {

project: Project!

}

mutation {

createProject(input: CreateProjectInput!): CreateProjectResult!

}

N+1 Prevention

Use DataLoader for all `team`, `user`, and `tasks` resolvers. Batch by parent ID and cache per-request.

Auth Directive

directive @auth(requires: UserRole!) on FIELD_DEFINITION

Query Complexity

Set max depth: 7, max complexity: 1000. Use `graphql-query-complexity` for cost analysis.

Tips for Best Results

  • 💡Start with your domain entities and relationships before writing resolvers
  • 💡Use cursor-based pagination from day one — offset pagination breaks with real-time data
  • 💡Return union types from mutations instead of throwing errors for expected failure cases
  • 💡Add a query complexity analyzer to prevent abusive nested queries in production