99% Smaller GraphQL Queries with AST Minification - WunderGraph

Jens Neuse
CEO & Co-Founder at WunderGraph
June 30, 2024 · 17min read
Edited on May 12, 2026 by Brendan Bondurant

TL;DR

Cosmo Router makes federated GraphQL faster by sending much smaller generated queries to subgraphs. AST minification reduces repeated selection sets, lowers parser overhead, and improves benchmark performance without requiring changes to subgraph code.

Make it work, make it right, make it fast. You've probably heard this mantra before.

In the context of GraphQL Federation Routers, this means that you should first be able to process some Queries. Next, you should make sure that all possible Queries and Schemas can be processed correctly, and that results match your expectations. Finally, you should optimize the performance of the overall system including Routers and Subgraphs.

This article is for platform engineers and API owners running GraphQL federation at scale who are hitting parser bottlenecks in subgraphs.

Key results:

Improving the performance of a GraphQL Federation Router is a continuous process.

Some optimizations are easy to spot, e.g. through profiling or monitoring.

Others require a much deeper understanding of the problem space and are harder to achieve. Most teams instinctively focus query optimization efforts on the router itself, but as we'll show, the real bottleneck often hides in the subgraph parser.

In this article, we'll talk about one such hard-to-find optimization: AST Minification. We'll demonstrate how Cosmo Router allows your Subgraphs to process Requests up to 25% faster compared to Apollo Router.

The Problem: The Subgraph as the Performance Bottleneck of GraphQL Federation

Why do GraphQL subgraphs become the performance bottleneck in federation?

To understand the problem, we need to look at the different stages of a GraphQL Federation Request. We can split the process into three main stages:

  1. Parsing
  2. Planning
  3. Execution

The Router needs to parse the incoming Query. Once the JSON is parsed, the Router needs to parse the GraphQL Document.

The document needs to be Normalized and Validated. After all of these steps, the Router can start planning the Query.

Planning is probably the most complex part. It's the process of analyzing the AST (Abstract Syntax Tree) of the Document and generating Subqueries for the Subgraphs. There are a lot of parameters that need to be considered during this process.

Once the planning phase is done, the Router can start executing the Plan.

Execution is the process of sending one or more Subqueries to the Subgraphs, some of which might depend on the results of other Subqueries, and then merging the results back together to form the final Response.

Now that you understand the three main stages of a GraphQL Federation Request, let's drill down into the core problem: The Subgraph as the performance bottleneck. Or more specifically, the parsing Phase of the Subgraph.

Subgraph Parser Performance: The Limiting Factor of GraphQL Federation

In our extensive research, we've discovered that the performance of GraphQL Parsers in Subgraphs is the limiting factor of the overall performance.

GraphQL is implemented in a variety of programming languages, and the performance of the Parser is usually not the main focus of the implementation.

The reason for this is that GraphQL Frameworks are usually built with a focus on monolithic implementations. In a monolithic implementation, or monograph, Queries are usually user-defined and not generated by a Router.

The use case that led us to the discovery of the Subgraph Parser as the limiting factor was a prospecting customer who wanted to break apart a monolithic GraphQL Server into multiple Subgraphs.

They had extensive experience with GraphQL and were heavy users of Abstract Types and Fragments, perfect conditions for the problem to manifest.

Federation Execution Flamegraph

Let's analyze the Flame Graph. The client makes a single POST Request to the Router. The Router then makes 3 Subgraph Requests sequentially.

Overall, the request takes ~2 seconds. The Graph shows that the Router spends roughly 300ms to Normalize the incoming Query. It then makes a very complex request to the first Subgraph, which shows "no activity" for at least 800ms.

I'd like to underline 40% of the overall request time is spent in the Subgraph Parser. The first Subgraph takes 1350ms in total, and 800ms of that time is spent in the Parser, that's ~60% of the time spent in the Subgraph.

Apollo Router vs. Cosmo Router: The Difference in Query Planning

We're not aware of the internals of how Apollo Router/Gateway plans Queries, but we can look at the generated Subgraph Queries to get an idea of how it works, and how it differs from Cosmo Router.

Let's say you've got a client that sends a Query to the Router.

The AST Minification Algorithm Explained: How Cosmo Router Reduces Query Size

The AST Minification Algorithm is very naive, yet it's very effective in reducing the size of the Query.

  1. Normalize the Query
    • Inline all Fragments
    • Deduplicate Fields in Selection Sets
  2. Sort all Selection Sets alphabetically
  3. Traverse the AST and create a Hash for each Selection Set
  4. Create a list of" Replacements" with all Selection Sets that have a Counter > 1
  5. Sort all Replacements by Depth, highest first
  6. Apply the Replacements Depth-first

In simple terms, the algorithm is looking for common Selection Sets in the Query and extracts them into Fragments.

Measuring the Impact of Cosmo AST Minification on Subgraph Performance

If we're honest, without AST Minification, the Cosmo approach to Query Planning has a significant disadvantage.

However, with the algorithm in place, the outcome was more than we've expected.

We've conducted a series of experiments with a tool called "GraphQL Faker".

Benchmarking the Query generated by Apollo Router

Benchmark of sending the Apollo Query to GraphQL Faker

P95 is 5.19s, throughput is 6.64 Requests per second.

Benchmarking the Query generated by Cosmo Router

Benchmark of sending the Cosmo Query to GraphQL Faker

P95 is 3.87s, throughput is 8.50 Requests per second.

Conclusion

Depending on the performance of your Subgraph Framework, you might achieve up to 25% more performance from your Subgraphs. Some Subgraph Frameworks might even benefit more, depending on their performance characteristics.

As we've shown in this article, there are fundamental differences in how different Routers plan Federated GraphQL Queries.