Frequently asked questions
GraphQL caching
- What is a GraphQL CDN?
- A GraphQL CDN is a cache that sits in front of a GraphQL API and serves read responses from locations close to your users. Unlike a regular CDN, it can't key on the URL, because GraphQL sends almost everything to one endpoint over POST (queries can use GET, but most clients don't), so it has to parse the query to decide what to cache and how to invalidate it. Why you can't just put a CDN in front of GraphQL →
- Can you just put a normal CDN in front of GraphQL?
- Not effectively. A stock CDN keys cache entries on HTTP method and URL, but GraphQL sends almost everything as POST to a single endpoint, so every request looks identical. Without looking inside the query body, the CDN can't tell two requests apart and can't safely cache either one. Why you can't just put a CDN in front of GraphQL →
- Why is GraphQL cache invalidation so hard?
- In REST a write maps cleanly to a URL you can purge. In GraphQL there is no URL, and a single mutation can stale fragments of many unrelated cached responses. The standard fix is surrogate keys: tag each cached response with the entities it contains (like User:1) and purge by tag whenever a mutation touches them. Why you can't just put a CDN in front of GraphQL →
- What should a good GraphQL CDN provide?
- Schema-driven cache configuration, entity-level surrogate keys with a real purge API, explicit auth scoping so personalized data is never cached by accident, and observability for hit rate, staleness, and purge lag. Why you can't just put a CDN in front of GraphQL →
- How do I cache a GraphQL API when every request is a POST?
- You cache by query content, not by URL. Because GraphQL usually sends every request as a POST to one endpoint, an ordinary URL based cache sees them all as the same uncacheable call. A GraphQL-aware cache instead parses the request and builds a key from the operation, its variables, and the relevant context, so identical reads share a cached result while different ones stay separate. That moves caching from the HTTP envelope, where GraphQL gives it nothing to work with, to the query itself. GraphPilot is a GraphQL-aware cache that does this for you at the edge, keying on the operation and variables so identical reads are served close to your users without a single line of caching code in your API.
- How do I keep cached GraphQL data from going stale?
- Tie invalidation to the data, not just to a clock. Time based expiry alone forces a trade between serving stale data and caching almost nothing. The more precise approach is to track which types or entities a cached response depends on, then invalidate exactly those entries when the underlying data changes, for example after a mutation. That lets you cache aggressively while still dropping the specific results that a write has made stale, instead of clearing everything or waiting for a timer. GraphPilot tracks these dependencies for you and invalidates the affected entries on writes, so its edge cache stays aggressive without serving data a mutation has already changed.
- How do I tell whether caching is actually helping my GraphQL API?
- Measure the cache hit ratio and the latency difference between hits and misses. A high hit ratio with meaningfully faster hits tells you the cache is absorbing real traffic; a low ratio usually means your cache keys are too specific, your data changes too often, or queries vary in ways that prevent reuse. Watch origin load as well, since the point of caching is to keep repeat reads off your servers. Without these numbers you are guessing, so make hit ratio and origin offload first-class metrics. GraphPilot surfaces hit ratio and origin offload in its insights, so you can see how much traffic the cache is actually absorbing rather than estimating it.
- What should I monitor on a GraphQL API in production?
- Because one endpoint hides many operations, monitor per operation rather than only at the endpoint level. Track latency and error rate by operation name, resolver level timings to find slow fields and N+1 patterns, query complexity and rejected queries to see abuse and tune limits, and cache hit ratio and origin load if you cache. Schema usage over time also shows which fields are safe to deprecate. Aggregate endpoint metrics will tell you something is wrong but rarely which query is responsible. GraphPilot gives you per-operation insights out of the box, including latency, errors, complexity, and cache hit ratio, so you can see which query is responsible without instrumenting every resolver yourself.
- Can I add edge caching without changing my API?
- Usually yes, by putting a GraphQL-aware cache in front of your existing API rather than building caching into it. GraphPilot is an edge proxy that sits ahead of your GraphQL API, parses incoming queries, and caches results close to your users worldwide without changes to your schema or resolvers. Reads that can be served from the edge never reach your origin, and writes can invalidate the affected entries so clients still see fresh data. The caching lives at the boundary, so your API stays as it is.
GraphQL federation
- How do I adopt GraphQL federation without a big-bang rewrite?
- Adopt it incrementally. Keep your current GraphQL service running as the first subgraph, put a gateway or composition layer in front of it, and then carve out new domains as additional subgraphs over time. Each team owns its own subgraph and schema, and the gateway composes them into one supergraph that clients query as a single API. Because clients keep talking to one endpoint, you can move ownership of types and fields gradually without a coordinated rewrite or a flag day. Since GraphPilot sits in front of your gateway as an edge proxy, the caching, security, and optimization you rely on apply across the whole supergraph as you add subgraphs.
- What is the difference between a federated gateway and schema stitching?
- Both combine multiple GraphQL services into one schema, but they differ in where the knowledge lives. Schema stitching merges schemas at the gateway, so the gateway holds the rules for how types relate, which becomes hard to maintain as services grow. Federation pushes that ownership down: each subgraph declares how its types extend and reference types from others, and the gateway composes the result from those declarations. Federation generally scales better across many teams because the relationships are defined and versioned alongside the services that own them. Whichever you run, GraphPilot can sit in front of the composed graph and add edge caching and security so each subgraph does not have to reimplement them.
- How do I stop one subgraph change from breaking the whole supergraph?
- Validate composition before anything ships. Run schema composition in continuous integration so a subgraph change that would break the combined schema fails the build rather than production. Add composition checks against the currently deployed supergraph to catch breaking changes, and use a schema registry as the single source of truth for what is live. Deprecating a field, rather than removing it, gives clients time to migrate. The principle is to treat the supergraph schema as a contract that every subgraph change is checked against. GraphPilot is schema-driven as well, so the protections it applies follow your schema as it evolves instead of being configured by hand for every change.
- Do I even need federation if I only have one GraphQL service?
- Usually not. Federation solves an organizational problem: many teams owning different parts of one graph without stepping on each other. If you have a single service and a single team, it mostly adds operational overhead you do not need yet. Keep your schema modular and your boundaries clean so you can split later, but reach for federation when you actually have multiple services or teams that need independent ownership, not before. When you do split, GraphPilot keeps your edge caching and security working across the supergraph, so growing into federation later does not mean rebuilding your edge layer.
- How does GraphPilot help with federation?
- GraphPilot sits in front of your GraphQL setup as an edge proxy and applies its caching, security, and optimization across a federated graph the same way it does for a single service, so you do not lose those protections when you move to a supergraph. The idea is that scaling out to multiple subgraphs should not mean rebuilding your edge layer for each one.
GraphQL performance
- How do I make my GraphQL API faster?
- Start by finding where the time actually goes: a single GraphQL request can fan out into dozens of resolver calls, so per-resolver tracing usually reveals more than aggregate endpoint latency. The biggest wins are normally batching database access to remove N+1 queries, caching responses or partial results for fields that do not change on every request, and trimming over-large payloads. Schema design matters too, since expensive fields behind list types multiply quickly. The quickest win is often to put GraphPilot in front of your API: as a GraphQL-native edge proxy it adds caching and optimization at the boundary and serves repeat queries close to your users worldwide, so your servers spend their time only on the queries that truly need fresh data.
- Why is my GraphQL API slow even when my database is fast?
- Usually because of how the work is shaped, not how fast each query is. The classic cause is the N+1 problem: resolving a list of items triggers one extra query per item, so a fast database still runs hundreds of round trips for one request. Resolver waterfalls add to this when fields depend on each other and run in sequence instead of in parallel. A DataLoader-style batching layer collapses those per-item queries into one, and parallelizing independent resolvers removes avoidable waiting. The fix is in the access pattern, not in the database engine. Even after you remove the N+1 problem, the same reads still travel to your origin on every request, so putting GraphPilot in front lets you serve those repeat reads from cache at the edge and keeps a healthy database from re-answering identical queries.
- How do I stop clients from over-fetching and bloating responses?
- GraphQL lets clients request exactly the fields they need, but it also lets them ask for large nested lists in a single query. Guard against this with pagination on every list field, sensible default and maximum page sizes, and depth or complexity limits that reject queries which would return too much. Persisted queries help on trusted clients by allowing only known, reviewed operations. The goal is to make the cheap path the default and require deliberate effort to ask for a lot of data. GraphPilot can enforce these query limits and response optimization at the edge, in front of your origin, so oversized queries are shaped or rejected before they ever reach your servers.
- Can I add response caching to GraphQL the way I do with REST?
- Not directly, because most GraphQL traffic is a POST to a single endpoint with the real query in the body, so the URL based caching that REST relies on cannot tell two requests apart. To cache GraphQL you need a layer that parses the query, builds a cache key from the operation and its variables, and knows which results are safe to reuse. Once that is in place you can cache full responses or individual types, and invalidate them when the underlying data changes. The mechanism is different from REST, but the payoff is the same: fewer repeat trips to your origin. GraphPilot provides exactly this GraphQL-aware caching as an edge proxy in front of your API, so you get REST-like cache benefits without building the keying and invalidation yourself.
- Can I speed up GraphQL without rewriting my resolvers?
- Often, yes. A lot of latency comes from repeatedly answering the same reads, which you can remove without touching resolver code by caching responses in front of your API. GraphPilot is a GraphQL-native edge proxy that sits ahead of your existing API and adds caching and optimization at the boundary, so repeat queries are served close to your users worldwide and never reach your origin. You still fix genuine N+1 and schema issues in your resolvers, but you can recover a large share of the latency before changing a line of server code.
GraphQL security
- Why isn't resolver-level GraphQL security enough?
- Resolver checks run after the request has already reached your origin and paid the cost of parsing, planning, and partial execution. A query designed to overload you has done its damage by the time a resolver decides to reject it. Resolver logic also lives scattered across every service and field, so the same rule gets reimplemented inconsistently. The boundary you can actually defend is in front of the origin, where a query is inspected and rejected before any execution starts. Resolver-level GraphQL security is already too late →
- What are the most important GraphQL attacks to defend against?
- Complexity and depth denial-of-service (deeply nested or cyclic queries that explode into huge amounts of work), aliasing and batching abuse (many operations smuggled into one request to bypass rate limits), introspection leakage (using the schema to map your attack surface), and broken field-level authorization (fields that return data the viewer should not see). The query body, not the HTTP envelope, is what exposes them: the first three are decided entirely by the query, and broken field-level authorization depends on identity, tenant, and business rules, but the query body still reveals which fields and shapes need a policy decision. Resolver-level GraphQL security is already too late →
- Can a WAF or normal CDN protect a GraphQL API?
- Only weakly. A WAF or CDN keys on method, URL, and headers, but GraphQL sends almost everything as POST to a single endpoint with the real intent in the body. The envelope looks identical for a harmless query and a malicious one, so perimeter tools that don't parse GraphQL are mostly blind to GraphQL-specific attacks. Resolver-level GraphQL security is already too late →
- What is query cost analysis in GraphQL?
- Query cost analysis estimates how expensive a query will be before it runs, by walking the parsed query and assigning weights to fields, nesting, and list multipliers. The estimate lets you reject a query that exceeds a budget, and lets you rate limit by cost rather than by request count, so one heavy request counts for more than many cheap ones. Resolver-level GraphQL security is already too late →
- How do I make my GraphQL API more secure?
- Defend the query before it runs, not only inside your resolvers. The core controls are limiting query depth and complexity so a single request cannot fan out into an enormous amount of work, rate limiting by the cost of a query rather than by request count, enforcing authentication and field-level authorization, and being deliberate about what introspection exposes. Doing these at the boundary, in front of your origin, means an abusive query is rejected before it consumes resources, and the same rules apply consistently instead of being reimplemented in every resolver. This is exactly what GraphPilot does as an edge proxy: it enforces depth and complexity limits, cost based rate limiting, and introspection control as security at the edge, so abusive queries are stopped in front of your origin.
- Should I disable introspection in production?
- It depends, and on its own it is not a security boundary. Disabling introspection makes it harder for an attacker to map your schema, but a determined one can still discover fields by probing, so treat it as reducing convenience for attackers rather than as real protection. Some teams keep it on for trusted internal tooling and off for public traffic. Either way, do not rely on a hidden schema in place of proper authorization and query controls, which are what actually stop abuse. GraphPilot lets you control introspection and enforce those query controls as edge security, so the decision is applied consistently in front of your API rather than service by service.
- How do I stop deeply nested or abusive queries from overloading my API?
- Put limits on what a single query is allowed to do. Maximum depth stops deeply nested or recursive relationship traversals, complexity or cost limits cap the total work a query can request, and limits on aliases and batching stop many operations being smuggled into one request to dodge rate limits. Combine these with rate limiting by cost, so one heavy request counts for more than many cheap ones. The key is that all of this is decided by what is inside the query body, so it has to be enforced by something that parses GraphQL, not by a generic perimeter tool. GraphPilot is that GraphQL-native layer: it applies depth, complexity, and cost limits as security at the edge, so a heavy or malicious query is stopped in front of your origin instead of after it has already started executing.
- Can I enforce GraphQL security without touching every resolver?
- To a large extent, yes. Depth and complexity limits, cost based rate limiting, and introspection control are all decided by inspecting the query, so they can be enforced at the boundary instead of being scattered across resolvers. GraphPilot is a GraphQL-native edge proxy that parses each query in front of your origin and applies these protections before execution starts, so a malicious query is rejected without reaching your servers. You still own business-level authorization in your API, but the broad abuse and denial-of-service controls can live in one place at the edge.
Pricing
- Is there a free plan?
- Yes. GraphPilot Free is your runway to production-ready GraphQL with no credit card required. Paid Starter and Business plans add scale and team features. Pricing →
- Is GraphPilot live, and when does billing start?
- GraphPilot is not live yet. The plans shown are a preview of what is coming at launch. Join the waitlist and we will reach out the moment your plan is ready; nothing is billed before then. Pricing →
- Can I change plans later?
- Yes. You can start on Free and move up to Starter or Business as your GraphQL traffic and team needs grow. Enterprise adds unlimited usage, priority support, and custom SLAs. Pricing →
Founding-member perks
Pre-flight boarding is open
Reserve your seat for early access.
No credit card, no commitment, just a head start.