Schema Design First Principles

A GraphQL schema is an API contract, so schema design should begin with the needs of API consumers and the domain rather than the shape of database tables.

A database model might contain:

users
user_profiles
user_addresses
user_login_metadata

That does not mean the GraphQL schema should expose those tables directly.

Instead, the API should model meaningful domain concepts:

type User {
  id: ID!
  name: String!
  profile: Profile
  addresses: [Address!]!
}

The GraphQL layer is an abstraction boundary.

Design around capabilities

Prefer operations that represent meaningful business actions:

cancelOrder(id: ID!): CancelOrderPayload!

rather than exposing implementation-oriented operations:

setOrderStatus(id: ID!, status: String!): Order!

The first expresses a business capability. The second exposes an internal state mutation that may allow invalid transitions.

Make invalid states difficult to represent

Use enums instead of arbitrary strings where values are constrained.

Use non-null types where a value is genuinely guaranteed.

Use input types for structured client data.

Use dedicated payload types when an operation has meaningful result metadata.

A well-designed schema communicates domain rules before a client ever reads the resolver implementation.

Good Schema Design Principles
Domain-oriented: Model business concepts rather than database tables
The API should remain useful even if persistence technology changes.
Explicit: Use meaningful types and enums
The schema should communicate important constraints.
Capability-oriented: Expose valid business actions
Operations should represent what clients are allowed to accomplish.
Key Takeaways
  • Do not automatically expose database models as GraphQL schema types.
  • Design around domain concepts and client capabilities.
  • Use the type system to communicate meaningful constraints.
  • A GraphQL schema should remain stable even when implementation details change.
Knowledge Check

Why should a GraphQL schema generally not mirror database tables directly?