Skip to main content
Version: 5.x.x

Getting Started


Using a JVM dependency manager, link graphql-kotlin-schema-generator to your project.

implementation("com.expediagroup", "graphql-kotlin-schema-generator", latestVersion)


graphql-kotlin-schema-generator provides a single function, toSchema, to generate a schema from Kotlin objects.

data class Widget(val id: Int, val value: String)
class WidgetQuery {
fun widgetById(id: Int): Widget? {
// grabs widget from a data source
class WidgetMutation {
fun saveWidget(value: String): Widget {
// some logic for saving widget
val widgetQuery = WidgetQuery()
val widgetMutation = WidgetMutation()
val schema = toSchema(
config = yourCustomConfig(),
queries = listOf(TopLevelObject(widgetQuery)),
mutations = listOf(TopLevelObject(widgetMutation))

will generate:

schema {
query: Query
mutation: Mutation
type Query {
widgetById(id: Int!): Widget
type Mutation {
saveWidget(value: String!): Widget!
type Widget {
id: Int!
value: String!

Any public functions defined on a query, mutation, or subscription Kotlin class will be translated into GraphQL fields on the object type. toSchema will then recursively apply Kotlin reflection on the specified classes to generate all remaining object types, their properties, functions, and function arguments.

The generated GraphQLSchema can then be used to expose a GraphQL API endpoint.


This function accepts four arguments: config, queries, mutations and subscriptions. The queries, mutations and subscriptions are a list of TopLevelObjects and will be used to generate corresponding GraphQL root types. See below on why we use this wrapper class. The config contains all the extra information you need to pass, including custom hooks, supported packages, and name overrides. See the Generator Configuration documentation for more information.

You can see the definition for toSchema in the source


toSchema uses Kotlin reflection to build a GraphQL schema from given classes using graphql-java's schema builder. We don't just pass a KClass though, we have to actually pass an object, because the functions on the object are transformed into the data fetchers. In most cases, a TopLevelObject can be constructed with just an object:

class Query {
fun getNumber() = 1
val topLevelObject = TopLevelObject(Query())
toSchema(config = config, queries = listOf(topLevelObject))

In the above case, toSchema will use topLevelObject::class as the reflection target, and Query as the data fetcher target.

Dynamic TopLevelObject#

In a lot of cases, such as with Spring AOP, the object (or bean) being used to generate a schema is a dynamic proxy. In this case, topLevelObject::class is not Query, but rather a generated class that will confuse the schema generator. To specify the KClass to use for reflection on a proxy, pass the class to TopLevelObject:

class Query {
fun getNumber() = 1
val query = getObjectFromBean()
val customDef = TopLevelObject(query, Query::class)
toSchema(config, listOf(customDef))
Last updated on by jgorman-exp