Schema and type system

The schema definition language, nullability, and why the schema is the contract your clients are generated from.

Schema definition language

A GraphQL service is described by one schema. Clients can introspect it, tools generate types from it, and the server validates every incoming document against it before executing anything.

type Query {
  post(id: ID!): Post
  posts(first: Int = 10, after: String): [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String!
  publishedAt: DateTime
  author: User!
  comments(first: Int = 5): [Comment!]!
}

type User {
  id: ID!
  name: String!
  posts: [Post!]!
}

type Comment {
  id: ID!
  body: String!
  author: User!
}

scalar DateTime
TypeUse
Int, Float, String, BooleanThe built-in scalars
IDAn opaque identifier, serialised as a string
[Post!]!A non-null list of non-null posts: two independent guarantees
enumA fixed set of allowed values, validated by the server
interfaceShared fields implemented by several object types
unionOne of several types that share no fields
inputA structured argument type, used mainly by mutations

Queries, mutations and the type system

query PostPage($id: ID!, $withComments: Boolean! = false) {
  post(id: $id) {
    id
    title
    author { name }
    comments(first: 3) @include(if: $withComments) {
      body
      author { name }
    }
  }
}

mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    post { id title }
    errors { field message }
  }
}
  • The client sends a document; the server parses and validates it against the schema, so a typo returns an error with a path instead of failing at runtime.
  • An exclamation mark marks a field as non-null. Nullability is part of the contract and is what drives client type generation.
  • Fragments keep a repeated selection in one place, and inline fragments let you select fields on an interface or union member.
  • @include and @skip make part of a shape conditional, so one document serves several screens.
  • Variables are typed and validated too, which also keeps user input out of the document text.
💡
Design the schema around what clients ask for, not around your database tables. Exposing rows one-to-one couples every client to your storage model, and any later refactor becomes a breaking change.

FAQ

What does N+1 mean in GraphQL?
One resolver loads a list, then a child resolver runs once per item and issues a query each time. The client sent a single query, but the server performed one plus N database queries.
Do I version a GraphQL schema?
Prefer evolution. Add fields, mark old ones deprecated with a reason, and remove them only after clients stop selecting them. Versioning the endpoint is a last resort.

Queries, mutations and resolvers When GraphQL beats REST, and its pitfalls

Last refreshed 2026-09-18.