Photo by chansu shin on Unsplash

On this page

This chapter follows Resolvers and execution.

NestJS organizes server code into modules, providers, and decorators. @nestjs/graphql with the Apollo driver generates SDL from TypeScript classes—a code-first workflow. The same resolver ideas apply in Apollo Server or GraphQL Yoga; Nest adds structure and dependency injection.

Install dependencies

From an existing Nest project:

Terminal window
pnpm add @nestjs/graphql @nestjs/apollo @apollo/server graphql
pnpm add graphql-ws ws subscriptions-transport-ws
pnpm add -D @types/ws

Match major versions to your Nest release; @nestjs/graphql 14 targets current Apollo Server integrations.

Register GraphQLModule

Import GraphQLModule in AppModule:

src/app.module.ts
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { join } from "node:path";
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), "schema.gql"),
sortSchema: true,
playground: process.env.NODE_ENV !== "production",
subscriptions: {
"graphql-ws": true,
},
context: ({ req }) => ({ req, userId: req.headers["x-user-id"] ?? null }),
}),
],
})
export class AppModule {}

autoSchemaFile writes SDL for reviews and codegen. Disable playground in production.

Define object and input types

src/books/dto/book.model.ts
import { Field, ID, ObjectType } from "@nestjs/graphql";
@ObjectType()
export class Book {
@Field(() => ID)
id!: string;
@Field()
title!: string;
}
src/books/dto/create-book.input.ts
import { Field, InputType } from "@nestjs/graphql";
@InputType()
export class CreateBookInput {
@Field()
title!: string;
}

Generated SDL mirrors these definitions for clients and tools.

Queries, mutations, and field resolvers

src/books/books.resolver.ts
import { Args, Mutation, Query, Resolver, ResolveField, Parent } from "@nestjs/graphql";
import { BooksService } from "./books.service";
import { Book } from "./dto/book.model";
import { CreateBookInput } from "./dto/create-book.input";
@Resolver(() => Book)
export class BooksResolver {
constructor(private readonly books: BooksService) {}
@Query(() => [Book])
books() {
return this.books.findAll();
}
@Mutation(() => Book)
createBook(@Args("input") input: CreateBookInput) {
return this.books.create(input);
}
@ResolveField(() => String)
slug(@Parent() book: Book) {
return book.title.toLowerCase().replace(/\s+/g, "-");
}
}

Register the resolver in a BooksModule with BooksService as a provider.

Validation with class-validator

Enable a global validation pipe and decorate inputs:

src/main.ts
import { ValidationPipe } from "@nestjs/common";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
await app.listen(3000);
}
src/books/dto/create-book.input.ts
import { Length } from "class-validator";
@InputType()
export class CreateBookInput {
@Field()
@Length(1, 200)
title!: string;
}

GraphQL validates types first; class-validator enforces domain constraints before resolvers run.

Request-scoped DataLoader

Provide a loader factory per request to batch relations:

src/authors/authors.loader.ts
import { Injectable, Scope } from "@nestjs/common";
import DataLoader from "dataloader";
import { AuthorsService } from "./authors.service";
@Injectable({ scope: Scope.REQUEST })
export class AuthorsLoader {
readonly byId: DataLoader<string, Author>;
constructor(authors: AuthorsService) {
this.byId = new DataLoader((ids) => authors.findByIds([...ids]));
}
}

Inject AuthorsLoader in a @ResolveField() for Book.author.

Subscriptions

Publish events from a service with @nestjs/graphql PubSub or an Redis-backed pub/sub for multi-instance deployments. Define a subscription resolver:

src/books/books.resolver.ts
import { Subscription } from "@nestjs/graphql";
@Subscription(() => Book, { filter: (payload, vars) => payload.bookAdded.id === vars.id })
bookAdded() {
return this.pubSub.asyncIterableIterator("bookAdded");
}

Clients connect with graphql-ws and the same auth headers or connection params you document in the security chapter.

Next: Schema design in GraphQL.

Search articles

Type a word to search published articles.

Open the search page