REST vs GraphQL: What Changed After We Adopted GraphQL in NestJS

REST vs GraphQL: What Changed After We Adopted GraphQL in NestJS

Written by
Written by

Jayendra J.

Post Date
Post Date

Jan 07, 2026

shares

When building backend applications, choosing the right API architecture has long-term consequences.

In this post, we’ll compare REST and GraphQL from a real NestJS project, explain where REST broke down for us, and show how GraphQL helped us ship faster with fewer API changes.

What Is a REST API?

REST (Representational State Transfer) is an architectural style where data is exposed via multiple endpoints, each representing a resource.

Example (REST)

GET /users/1
GET /users/1/posts
GET /users/1/profile

Each endpoint returns a fixed data structure, defined by the backend.

Advantages of REST

Problems We Faced with REST

As the application grew, we started noticing issues:

None of these problems appeared early on. REST worked well when the application was small and the frontend requirements were stable.

The friction started when different screens needed different data shapes, and frontend iteration speed increased.

What Is GraphQL?

GraphQL is a query language for APIs that allows the client to request exactly the data it needs — nothing more, nothing less.

Instead of many endpoints, GraphQL exposes a single endpoint.

Example (GraphQL)

query {
  user(id: 1) {
    name
    email
    posts {
      title
    }
  }
}

The key shift with GraphQL is data ownership: the backend defines what is possible, while the frontend decides what is necessary.

REST vs GraphQL: Key Differences

Why We Chose GraphQL for Our NestJS Project

We were working on a NestJS backend powering a frontend-heavy application (React and mobile clients). Each screen needed a slightly different version of the same data.

With REST, this led to:

GraphQL removed these trade-offs. One endpoint, flexible queries, and frontend-driven data needs — all without backend churn.

GraphQL in NestJS: Setup & Real-World Examples You Actually Need

Most GraphQL tutorials stop at simple CRUD examples.

In real projects, we deal with nested relations, conditional fields, pagination, and optimized queries.

Let’s cover proper setup first, then move to important real-world GraphQL examples.

GraphQL Setup in NestJS (Step-by-Step)

1. Install Required Packages

npm install @nestjs/graphql @nestjs/apollo graphql

2. Configure GraphQL Module

app.module.ts

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: true,
      playground: true,
    }),
  ],
})
export class AppModule {}

— Auto-generates the schema

— Enables GraphQL Playground at /graphql

3. Recommended Folder Structure

src/
├── user/
│   ├── user.module.ts
│   ├── user.resolver.ts
│   ├── user.service.ts
│   ├── user.entity.ts

This structure keeps GraphQL logic modular, readable, and scalable as the schema grows.

Important GraphQL Examples (Production-Level)

Example 1: Nested Relations (User → Posts → Comments)

Why this matters:

Frontend applications often need deeply related data in a single request. With REST, this usually requires multiple API calls or custom endpoints.

GraphQL Query

query {
  user(id: 1) {
    name
    email
    posts {
      title
      comments {
        message
        author {
          name
        }
      }
    }
  }
}

Resolver Example

@Resolver(() => User)
export class UserResolver {
  constructor(private userService: UserService) {}

  @Query(() => User)
  user(@Args('id') id: number) {
    return this.userService.findUserWithPosts(id);
  }
}

— Single request

— Exact data needed

— No over-fetching

In production, this pattern pairs well with tools like DataLoader to avoid N+1 query issues.

Example 2: Conditional Fields (Frontend-Controlled Data)

Problem in REST

You often return extra data even when the frontend doesn’t need it.

GraphQL Query (Admin View)

query {
  user(id: 1) {
    name
    email
    role
    subscription {
      status
      expiresAt
    }
  }
}

GraphQL Query (Public View)

query {
  user(id: 1) {
    name
  }
}

The backend remains unchanged while the frontend controls the response shape.

Example 3: Pagination (Very Important)

GraphQL Query

query {
  users(page: 1, limit: 10) {
    data {
      id
      name
    }
    meta {
      total
      page
      lastPage
    }
  }
}

GraphQL Types

@ObjectType()
class UserPagination {
  @Field(() => [User])
  data: User[];

  @Field()
  total: number;

  @Field()
  page: number;

  @Field()
  lastPage: number;
}

Resolver

@Query(() => UserPagination)
users(
  @Args('page') page: number,
  @Args('limit') limit: number,
) {
  return this.userService.paginate(page, limit);
}

— Clean pagination

— Frontend-friendly

— No custom REST response structure

Whether you return pagination metadata as a meta object or flatten it is less important than keeping the contract consistent across queries.

Example 4: Mutations with Validation

Create User Mutation

mutation {
  createUser(input: {
    name: "Jayendra"
    email: "jay@gmail.com"
  }) {
    id
    name
  }
}

Input DTO

@InputType()
export class CreateUserInput {
  @Field()
  name: string;

  @Field()
  email: string;
}

Mutation Resolver

@Mutation(() => User)
createUser(@Args('input') input: CreateUserInput) {
  return this.userService.create(input);
}

— Strong typing

— Validation-ready

— Cleaner than REST body parsing

Why These Examples Are Important

These are real production scenarios — not tutorial-level CRUD.

GraphQL helps you:

This is where GraphQL delivers its real value in a NestJS application.

Final Thoughts

REST is still a solid choice — it’s not outdated, and for simple or stable APIs, it may be the better option.

But for modern applications with multiple clients, fast-moving frontends, and complex data requirements, GraphQL — especially with NestJS — offers a more flexible and future-proof approach.

For our team, switching to GraphQL improved developer experience, reduced API churn, and made frontend-backend collaboration significantly smoother.

If you’re building APIs with NestJS and juggling multiple frontend clients, I’d strongly recommend evaluating GraphQL early — before REST complexity starts to accumulate.