Skip to content

Security: Depth Limiting and Query Cost

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Security: Depth Limiting and Query Cost. We cover key concepts, practical examples, and best practices to help you master this topic.

GraphQL's flexibility makes it vulnerable to denial-of-service attacks through deeply nested queries, expensive field combinations, and circular queries. Security middleware prevents abuse by limiting query depth, cost, and execution time.

What You'll Learn

  • Query depth limiting
  • Query complexity/cost analysis
  • Rate Limiting for GraphQL endpoints
  • Persisted queries for production APIs
  • Timeout and execution budgets

Why It Matters

A malicious client can craft a query that grows exponentially (e.g., friends.friends.friends). Without security measures, such queries can crash your server or exhaust database connections.

Real-World Use

GitHub sets a depth limit of 7 on their GraphQL API. Shopify uses query cost analysis to reject expensive queries before execution. Apollo Studio provides cost analysis tools for production graphs.

flowchart LR
    Request[Incoming Query] --> DepthCheck[Depth Limit Check]
    DepthCheck -->|Pass| CostCheck[Complexity Analysis]
    DepthCheck -->|Fail| Reject[Reject: Too Deep]
    CostCheck -->|Pass| RateLimit[Rate Limit Check]
    CostCheck -->|Fail| Reject2[Reject: Too Expensive]
    RateLimit -->|Pass| Execute[Execute Query]
    RateLimit -->|Fail| Reject3[Reject: Rate Limited]

Teacher Mindset

Treat security as a layered defense. Depth limiting catches obviously malicious queries. Complexity analysis catches expensive but legitimate queries. Rate limiting prevents abuse at volume.

Code Examples

// Example 1: Depth limiting with graphql-depth-limit
const depthLimit = require('graphql-depth-limit');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [depthLimit(7)]
});
// Example 2: Query complexity analysis
const { createComplexityLimitRule } = require('graphql-validation-complexity');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    createComplexityLimitRule(1000, {
      onCost: (cost) => console.log(`Query cost: ${cost}`)
    })
  ]
});
// Example 3: Rate limiting plugin
const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    {
      requestDidStart: async ({ request }) => {
        const key = request.http?.headers.get('x-api-key');
        const isAllowed = await rateLimiter.check(key, 100, 60);
        if (!isAllowed) {
          throw new Error('Rate limit exceeded');
        }
      }
    }
  ]
});

Common Mistakes

  • Setting depth limits too low, breaking legitimate queries with deep nesting
  • Only limiting depth without cost analysis for expensive fields
  • Using IP-based rate limiting for APIs that share IPs behind NAT
  • Not applying security rules to subscriptions and Websocket connections
  • Relying solely on client-side query limits

Practice

  1. Add depth limiting to your GraphQL server with a limit of 5.
  2. Implement query complexity analysis with a cost budget of 500.
  3. Add rate limiting based on API keys.
  4. Implement persisted queries for a production-ready setup.
  5. Challenge: Build a custom cost analysis function that assigns higher costs to database-heavy fields.

FAQ

What is a reasonable depth limit?

5-7 levels is typical. Analyze your schema to determine the maximum depth legitimate queries need.

How does query cost analysis work?

Each field gets a cost value. The total query cost is the sum of all requested field costs. Queries exceeding the budget are rejected.

What are persisted queries?

Persisted queries store approved query strings on the server. Clients send only the query hash, preventing arbitrary queries.

Should I limit subscription complexity?

Yes. Subscriptions can also be expensive. Limit the number of active subscriptions per client and monitor event publication rates.

How do I handle security for federated graphs?

Apply security rules at the gateway level for depth and cost. Each subgraph should also independently validate and rate limit requests.

Mini Project

Add three security layers to your library API: depth limiting (max 6), cost analysis (budget 1000), and rate limiting (100 requests per minute per API key). Test each layer with malicious queries.

What's Next

Next, you will build a complete GraphQL project that integrates all concepts from this section.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro