skip to content

Schema-First Development

Spring GraphQL is schema-first: SDL files define the types and operations, and the runtime wiring binds them to your handlers. Interviewers ask why schema-first is preferred, and 'the contract is the artifact everyone reviews' is the answer.

part ofSpring for GraphQLoverview, primer and where to startread it →
on this pageshow

questions

5

What is schema-first GraphQL development in Spring for GraphQL, and where do you put the schema files?

level: juniorimportance: must knowfreq 70%

answer

  1. SDL .graphqls = source of truth
  2. classpath:graphql/**/ default location
  3. folder graphql, extension .graphqls
  4. @QueryMapping resolves fields
  5. schema-first vs code-first

basics

~10 s

You write the GraphQL schema by hand in SDL (.graphqls) files. Spring Boot loads them from classpath:graphql/ by default and builds the schema from them; your Java code just supplies the data.

solid answer

~40 s

Schema-first means the GraphQL schema — the contract of types, queries, and mutations — is authored by hand in SDL (Schema Definition Language) text files, not generated from Java classes. In a Spring Boot app using the spring-boot-starter-graphql, you place .graphqls (or .gql) files under src/main/resources/graphql/. On startup the GraphQL auto-configuration discovers every file matching classpath:graphql/**/, parses and merges them into one schema, and exposes it. You then write controller methods (e.g. @QueryMapping) that resolve each field. The schema file is the single source of truth: the API shape is defined there, and Java code only fills in how each field's data is fetched. This contrasts with code-first, where the schema is derived programmatically from code.

code

java · 19 lines
java
// src/main/resources/graphql/schema.graphqls
//   type Query { book(id: ID!): Book }
//   type Book  { id: ID!  title: String!  author: String }

@Controller
class BookController {

    private final BookRepository repository;

    BookController(BookRepository repository) {
        this.repository = repository;
    }

    // Field name 'book' under type Query is matched by method name.
    @QueryMapping
    public Book book(@Argument String id) {
        return repository.findById(id).orElse(null);
    }
}

go deeper

for a junior

Know: hand-written SDL, .graphqls files under resources/graphql/, code supplies data.

for a middle

Explain the default location property and that multiple files merge into one schema.

for a senior

Contrast schema-first vs code-first and articulate why Spring favors schema-first (contract-as-doc, versioned SDL).

for a principal

Discuss governance: SDL as a reviewable, diffable contract; schema linting and breaking-change detection in CI.

**GraphQL** is a query language for APIs where the server publishes a strongly-typed **schema** describing every type, query, and mutation clients can use; clients ask for exactly the fields they want. **Schema-first vs code-first.** There are two ways to define that schema. *Code-first* builds the schema programmatically from Java/Kotlin (e.g. GraphQL-Java's `GraphQLObjectType` builders or a library like Netflix DGS annotations). *Schema-first* — the approach Spring for GraphQL is built around — means you write the schema by hand in **SDL (Schema Definition Language)**, a plain-text notation, and keep it as `.graphqls` files. SDL is the source of truth; code only implements resolvers. **Where the files go.** `spring-boot-starter-graphql` auto-configures schema loading. By default it looks at the property `spring.graphql.schema.locations`, whose default value is `classpath:graphql/**/`, and file extensions from `spring.graphql.schema.file-extensions` defaulting to `.graphqls,.gqls`. So conventionally you create `src/main/resources/graphql/schema.graphqls`. You can split the schema across many files in that folder (and subfolders, because of `**/`); Spring reads and **merges** them all into one schema. You can also override the location property to point elsewhere. **What SDL looks like.** A minimal schema: ```graphql type Query { book(id: ID!): Book } type Book { id: ID! title: String! author: String } ``` `type Query` is the special root type for reads; `type Mutation` for writes; `type Subscription` for streaming. `!` means non-null, `[Book]` a list. **How Spring uses it.** On startup the auto-configured `GraphQlSource` bean reads the SDL, builds a `graphql.schema.GraphQLSchema`, and wires each field to a resolver. Resolvers are typically **annotated controller** methods: `@QueryMapping Book book(@Argument String id)`. The method name matches the schema field (or you name it explicitly). Java DTO field names are matched to schema fields automatically for simple properties. **Gotchas.** (1) The schema file must exist — with no `.graphqls` under the location and no programmatic schema, startup fails ("No schema files"). (2) The folder is `graphql`, not `graphqls`; the *extension* is `.graphqls`. (3) Every non-scalar field a client can request needs a resolver or a matching DTO property; Spring Boot can log a **schema-mapping inspection report** warning about schema fields with no backing. **When to use schema-first.** It is the idiomatic Spring choice and preferred when the API contract is designed up front, shared with front-end/other teams, or reviewed independently of implementation — the SDL doubles as human-readable documentation and can be linted/diffed in version control.

  • What is the default classpath location and file extension Spring scans for schema files?
    Location default is classpath:graphql/**/ (property spring.graphql.schema.locations); extensions default to .graphqls and .gqls (spring.graphql.schema.file-extensions). Conventionally src/main/resources/graphql/schema.graphqls.
  • If you have three .graphqls files in that folder, what happens?
    Spring reads and merges all matching files into a single GraphQLSchema. You can split one logical schema across many files, e.g. one per domain type.

context

open as a page

How does Spring Boot turn your .graphqls files into a working schema — what is GraphQlSource and how are fields wired to code?

level: middleimportance: should knowfreq 55%

basics

~10 s

The auto-configured GraphQlSource bean reads the SDL files, builds the GraphQLSchema, and applies the runtime wiring. Annotated controllers (@QueryMapping, @MutationMapping, @SchemaMapping) become the data fetchers for each schema field.

open as a page

What is RuntimeWiringConfigurer and when do you need one instead of just annotated controllers?

level: seniorimportance: should knowfreq 45%

basics

~20 s

RuntimeWiringConfigurer is a bean that customizes how the schema is wired at build time. You add one to register custom scalar types, TypeResolvers for interfaces/unions, or directive wiring — things annotated @QueryMapping controllers can't express.

open as a page

Why does Spring for GraphQL favor schema-first over code-first, and what are the trade-offs and customization hooks?

level: seniorimportance: nice to knowfreq 35%

basics

~20 s

Schema-first keeps the SDL contract as the single, human-readable, version-controlled source of truth, decoupled from Java. Trade-off: you hand-write and hand-sync SDL with resolvers; there's no compile-time link, so a schema inspection report catches mismatches.

open as a page

How does Spring merge multiple .graphqls files, and how do you use `extend type` and split a large schema across files?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

All files matching classpath:graphql/**/ are parsed and merged into one schema, so you can split types across files by domain. To add fields to a type defined elsewhere, use extend type Query { ... }. The base type must be defined exactly once across the merged set.

open as a page