Skip to content

GraphQL Under-Fetching — Solving the N+1 Problem with Batched Queries

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about GraphQL Under. We cover key concepts, practical examples, and best practices to help you master this topic.

Under-fetching occurs when an API does not return enough data in a single response, forcing clients to make multiple requests. GraphQL solves this by allowing nested queries that fetch related data in one round-trip.

What You'll Learn

  • The N+1 problem in REST APIs
  • How GraphQL nested queries prevent under-fetching
  • Balancing query depth with performance

Why It Matters

Under-fetching multiplies network requests, increasing latency and complexity. GraphQL's nested query capability eliminates this source of performance problems.

Code Examples

# GraphQL: Fetch user and their posts in one query
query {
  user(id: "1") {
    name
    email
    posts {
      title
      content
      comments {
        text
        author {
          name
        }
      }
    }
  }
}
// REST under-fetching: Multiple round-trips
// Request 1: Get user
const user = await fetch('/api/users/1').then(r => r.json());
// Request 2-5: Get each post (N+1 problem!)
const posts = await Promise.all(
  user.postIds.map(id => fetch(`/api/posts/${id}`).then(r => r.json()))
);
// Request 6-15: Get comments for each post
const comments = await Promise.all(
  posts.flatMap(post =>
    post.commentIds.map(id => fetch(`/api/comments/${id}`).then(r => r.json()))
  )
);
// Total: 15+ HTTP requests!

// GraphQL: One request for everything
const query = `{
  user(id: "1") {
    name
    posts {
      title
      comments { text }
    }
  }
}`;
const { data } = await fetch('/graphql', {
  method: 'POST',
  body: JSON.stringify({ query })
}).then(r => r.json());
// Total: 1 HTTP request!
# Measuring round-trips
import time

# REST approach (many requests)
start = time.time()
user = requests.get('https://api.example.com/users/1').json()
post_ids = [1, 2, 3]
posts = [requests.get(f'https://api.example.com/posts/{pid}').json() for pid in post_ids]
rest_time = time.time() - start
print(f'REST: {1 + len(post_ids)} requests in {rest_time:.2f}s')

# GraphQL approach (one request)
start = time.time()
query = '{ user(id: 1) { posts { title content } } }'
result = requests.post('https://api.example.com/graphql', json={'query': query}).json()
gql_time = time.time() - start
print(f'GraphQL: 1 request in {gql_time:.2f}s')
print(f'Speedup: {rest_time/gql_time:.1f}x')

Common Mistakes

1. Creating Deeply Nested Queries

Deep nesting can cause performance issues. Limit query depth to 3-5 levels.

2. Not Using DataLoader to Batch Database Queries

Without batching, each nested field causes a separate database query.

Sometimes separate queries are better for Caching or Lazy Loading.

4. Forgetting About Circular References

Ensure your schema does not allow infinite nesting cycles.

5. Ignoring Query Complexity Limits

Large nested queries can overload your server. Implement complexity analysis.

Practice Questions

  1. What is the N+1 problem?
  2. How does GraphQL solve under-fetching?
  3. What is query depth and why does it matter?
  4. Can GraphQL queries still cause under-fetching?
  5. When might separate queries be better than one nested query?

Answers:

  1. When fetching a list of items requires N additional queries for each item.
  2. By allowing nested queries that fetch related data in a single request.
  3. The number of nesting levels. Deep queries can be expensive to resolve.
  4. No, because the client specifies exactly what data is needed.
  5. For independent data that is cached separately or loaded on demand.

Challenge: Take a REST API that requires 5+ requests to render a page and design a single GraphQL query that fetches all the data. Compare the total response time before and after.

FAQ

Does GraphQL guarantee no under-fetching?

Yes, because the client specifies exactly what data is needed. If the schema supports the requested fields, all data comes in one response.

Can GraphQL queries be too large?

Yes. Implement query depth limiting and complexity analysis to prevent overly large queries.

How does DataLoader help with under-fetching?

DataLoader batches and caches database queries, preventing N+1 at the resolver level even with nested queries.

Is under-fetching always bad?

Not always. Sometimes lazy loading data only when needed improves initial page load time.

How does under-fetching compare to over-fetching?

Under-fetching causes too many requests; over-fetching sends too much data per request. GraphQL solves both.

Mini Project

Build a benchmark tool that measures total response time and number of requests for a REST API vs a GraphQL API fetching the same nested data. Generate a report showing the performance difference.

What's Next

Deep dive into GraphQL SDL for schema definition, then learn about object types and field definitions.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro