Building with Yoga
This is where everything lands. You have designed schemas, written resolvers, added mutations, handled pagination and errors, secured the graph, and learned how to type, test, and federate it. This lesson assembles those ideas into one small, cohesive TypeScript service using GraphQL Yoga — a batteries-included GraphQL server that runs anywhere Node does — and gives you a runnable project to take with you.
The three pieces of a Yoga service
Section titled “The three pieces of a Yoga service”A Yoga server is built from the same three pieces every GraphQL server has, now wired together explicitly:
- typeDefs — the schema in SDL. This is your contract, written schema-first (the Schema-First vs Code-First lesson). It holds a
Queryfor reads and aMutationfor writes. - resolvers — the functions that fulfil each field. You met these in Queries & Resolvers and extended them with writes in the mutations module.
- context — a per-request object Yoga builds once and threads into every resolver as the third argument. It is where request-scoped things live: the current user, a database handle, a request id. It is the clean place to put what Security & Performance cares about.
Yoga takes those three and turns them into an HTTP server with a built-in GraphiQL playground, sensible error handling, and subscriptions support — no boilerplate of your own.
flowchart TD TypeDefs["typeDefs (SDL contract)"] Resolvers["resolvers (fulfil each field)"] Schema["Executable schema (createSchema)"] Context["createContext (per request)"] Yoga["createYoga"] Http["HTTP server + GraphiQL"] TypeDefs --> Schema Resolvers --> Schema Schema --> Yoga Context --> Yoga Yoga --> Http
How context threads through
Section titled “How context threads through”Context is the piece newcomers under-use. You define a createContext function that runs per request — read a header, look up the caller — and return an object. Yoga passes that object to every resolver as the third argument, so any resolver can read who is asking without re-parsing the request:
function createContext() { // Runs once per request; the return value is the resolver context. return { greetingPrefix: 'Hello' };}
const resolvers = { Query: { // The third argument is the context object above. hello: (_parent: unknown, args: { name: string }, ctx: { greetingPrefix: string }) => `${ctx.greetingPrefix}, ${args.name}!`, },};That keeps resolvers pure of request plumbing: they ask ctx for what they need, and the wiring lives in one place.
A runnable Yoga server — query, mutation, and context
Section titled “A runnable Yoga server — query, mutation, and context”The project below is a complete schema.ts: it exports typeDefs (a small schema with one query and one mutation) and resolvers (with an in-memory store and a context-aware greeting). Press Open in StackBlitz to spin up the real GraphQL Yoga server in your browser, then open the GraphiQL playground it prints and try the operations.
Needs the Node.js runtime — open in StackBlitz to run.
Once it is running, try the read first:
{ greeting(name: "Graph") messages { id text } }greeting proves context flowed in — the "Hello" prefix came from createContext, not the resolver. Then run the write and read again:
mutation { postMessage(text: "Built it end to end") { id text } }Query messages once more and your new message is there. In a few lines you exercised a query, a mutation, request context, and an in-memory store — the same shape every production Yoga service has, just smaller.
Where this fits in the whole course
Section titled “Where this fits in the whole course”This service is a microcosm of the entire book. The typeDefs are schema design. The resolvers are the queries-and-resolvers and mutations work. context is where security and performance hook in. Add codegen and tests from earlier in this module and you have a typed, tested service; split it by domain and put a gateway in front and you have the federation lesson. One small file, every idea.