100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
GraphQL

The GraphQL Schema

How GraphQL's Schema Definition Language describes types, fields, and operations as the contract between client and server.

GraphQL FoundationsIntermediate10 min readJul 10, 2026
Analogies

The GraphQL Schema

The schema is the heart of any GraphQL API: written in Schema Definition Language (SDL), it declares every object type, field, argument, and operation the API supports, and serves as a strongly-typed contract that both client and server agree to. Because the schema is introspectable, tools like GraphiQL, Apollo Studio, and GraphQL Code Generator can read it at runtime or build-time to power autocomplete, documentation, and even generate typed client code, which is a level of tooling REST's looser, often out-of-band documentation can't always guarantee stays accurate.

🏏

Cricket analogy: The schema is like the official Laws of Cricket document — every player, umpire, and broadcaster works from the same defined set of terms (LBW, no-ball, boundary) so there's no ambiguity about what's legal.

Defining Types and Fields

Object types in SDL are declared with the type keyword and list their fields along with each field's type, such as type Book { title: String, pages: Int, author: Author }. Two modifiers change a field's nullability and cardinality: an exclamation mark makes a type non-null, meaning the server guarantees a value will always be present (String! can never return null), and square brackets denote a list, so [String!]! is a non-null list of non-null strings. Scalar types like String, Int, Float, Boolean, and ID form the leaves of the graph, while object types like Author or Book let fields reference other types, building the graph structure that gives GraphQL its name.

🏏

Cricket analogy: Marking a field String! in a schema is like a scorecard guaranteeing every completed innings will always list a total — never blank — the same certainty a non-null type promises.

graphql
type Author {
  id: ID!
  name: String!
  books: [Book!]!
}

type Book {
  id: ID!
  title: String!
  pages: Int
  author: Author!
}

type Query {
  book(id: ID!): Book
  books: [Book!]!
}

type Mutation {
  addBook(title: String!, authorId: ID!, pages: Int): Book!
}

Root Operation Types: Query, Mutation, Subscription

Every GraphQL schema defines up to three root operation types: Query, which exposes all the read operations clients can perform and must be present in every schema; Mutation, which exposes operations that create, update, or delete data and, by convention, returns the modified object so the client can immediately see the result; and Subscription, which exposes long-lived operations that push real-time updates to clients over a protocol like WebSockets, useful for features like live chat messages or live sports scores. Each root type's fields work exactly like any other object type's fields — they can take arguments and return scalars or object types — but they are special in that they represent the actual entry points into the graph.

🏏

Cricket analogy: Query is like checking the live scoreboard (read-only), Mutation is like the third umpire officially overturning a decision (a write that changes the match record), and Subscription is like a live radio commentary feed pushing every ball's outcome as it happens.

The Query root type is the only one mandatory in every GraphQL schema; Mutation and Subscription are optional and only need to be defined if your API supports writes or real-time push updates, respectively.

Schema-First vs Code-First Development

Schema-first development means writing the SDL file by hand first, treating it as the definitive contract, and then implementing resolver functions that satisfy each field — this keeps the schema readable and reviewable independent of any programming language, and tools like GraphQL Code Generator can produce typed client and server code from it. Code-first development inverts the order: developers write ordinary code (TypeScript classes with decorators in TypeGraphQL, or JavaScript objects in Nexus) and the schema is generated automatically from that code at build or runtime, which keeps the schema and the implementation from drifting apart since they're the same source, at the cost of the SDL no longer being a hand-authored, human-first artifact.

🏏

Cricket analogy: Schema-first is like drafting the match playing conditions document before a single ball is bowled, while code-first is like a franchise auto-generating the conditions summary from the actual ground's configured settings.

Not every schema change is safe: removing a field, renaming a field, or tightening a nullable field to non-null are all breaking changes for existing clients, even though adding a brand-new field or type is not. Schema-diffing tools like Apollo's schema checks should run in CI to catch breaking changes before deployment.

  • The schema, written in SDL, is the strongly-typed contract every GraphQL client and server agrees to.
  • Object types declare fields with types; ! marks non-null and [] marks a list, e.g. [String!]! is a non-null list of non-null strings.
  • Query is the only mandatory root type; Mutation handles writes and Subscription handles real-time push updates.
  • Mutations conventionally return the object they just modified so clients can immediately reflect the change.
  • Schema-first authoring treats the SDL as the source of truth; code-first generates the schema from application code.
  • Adding fields is safe, but removing fields, renaming fields, or making a nullable field non-null are breaking changes.

Practice what you learned

Was this page helpful?

Topics covered

#GraphQL#GraphQLStudyNotes#WebDevelopment#TheGraphQLSchema#Schema#Defining#Types#Fields#SQL#APIs#StudyNotes#SkillVeris