GraphPilot: GraphQL edge proxy for automatic caching, security and optimization

GraphPilotWE FLY THE COMPLEXITY SO YOU DON'T HAVE TO
About

Built for GraphQL.

Works with everything.

GraphPilot is a GraphQL-native proxy, written in Rust, that sits in front of your API and handles caching, security, and optimization for you. It reads your schema to work out which queries to cache, how long to hold them, and which entries to clear when a mutation changes the data underneath. There are no application-owned cache keys to maintain, no purge scripts to write, and no client-side cache plumbing to keep in sync once the proxy is in front of your API.

That is harder than it sounds, because GraphQL breaks the assumptions most infrastructure is built on. Most traffic goes to the same endpoint, so ordinary HTTP caching has nothing to key on. A single query can nest deep enough to pull far more work out of your servers than you intended. And with no fixed response shape, clearing the cache after a write is one of the harder problems to get right.

Client

Web · Mobile · Server

Request
Response
GraphPilot
PROTECT CACHE OPTIMIZE
Request
Response

Origin

GraphQL · REST · HTTP

New York Los Angeles Chicago Toronto São Paulo London Frankfurt Amsterdam Paris Stockholm Mumbai Singapore Tokyo Sydney + 65 more

GraphPilot runs on a global edge network that sits between your clients and your origin, close enough to most users to serve a cached read without crossing regions. Anything it can't answer from cache, it checks, deduplicates, and forwards upstream clean, so your origin only handles what has to reach it. That work falls into four areas, each one handled at the edge.

Edge Cache

GraphQL reads served from the nearest PoP, with schema-aware invalidation after writes and empty-result caching handled correctly.

Learn more
Edge Optimization

Request collapsing, persisted operations, GET-cacheable reads, and faster edge transport for leaner API traffic.

Learn more
Edge Security

GraphQL-aware abuse protection, auth policies, query-shape controls, and operation rules before traffic reaches origin.

Learn more
Insights

Operation-level traffic, cache health, security activity, and edge geography without SDKs or log shipping.

Learn more
Why GraphPilot

Six reasons.

To fly with GraphPilot.

Schema-driven

Your schema is the single source of truth.

In GraphQL the schema is already the contract every client and service agrees on. GraphPilot makes it the source of truth for behavior too: caching, auth, rate limits, and invalidation are declared as directives on the fields they govern, instead of sitting in a separate dashboard or config repo that quietly drifts out of sync.

Read more
Automatic cache metadata

Clients write GraphQL. We handle the keys.

GraphPilot derives the metadata it needs for cache management automatically. Clients never decide which fields make a response cacheable. That responsibility moves to the backend team and lives in the schema.

Read more
Isolated runtime

Isolated per tenant and service.

An isolated, high-performance Rust edge runtime per tenant and service. Never a shared multi-tenant runtime.

Universal edge

GraphQL, REST, any HTTP.

One edge in front of every API you run.

European

European, under German law.

GDPR-native · EUR pricing · German jurisdiction.

Cloud roadmap

Provider-agnostic by design.

A provider-agnostic architecture, with enterprise and sovereign EU deployment options planned.

Founding-member perks

Pre-flight boarding is open

Reserve your seat for early access.
No credit card, no commitment, just a head start.

Schema-driven

One schema.

One truth.

With GraphPilot, your GraphQL schema becomes the configuration. Caching, authorization, rate limits, and invalidation are declared as directives right next to the fields they govern, instead of being scattered across config files, dashboards, and purge scripts.

Because the policy travels with the type, a schema change carries its edge behavior with it. The rules are versioned in the same repository, reviewed in the same pull request, and readable by everyone who already works with the schema.

schema.graphql
type Product
  @cacheControl(maxAge: 300, scope: PUBLIC) {
  id: ID!
  name: String! @cacheControl(maxAge: 600)
  price: Float
    @cacheControl(maxAge: 120, scope: PUBLIC)
    @cacheControl(maxAge: 60, scope: PRIVATE)
}

# Cache, authorization, rate-limit, and invalidation
# policies are declared alongside the fields they
# govern, reviewed in the same pull request as the
# schema, and versioned with it.

Versioned with your types

Cache TTL, auth rules, and invalidation keys live next to the field definitions they govern. When a type changes, the policy changes in the same pull request.

Visible to every team

Backend engineers, platform engineers, and API consumers all read the same schema. They see the same edge behavior without separate docs to maintain.

Works alongside what you have

Apollo Federation cache hints and HTTP cache-control headers keep working. GraphPilot extends the schema you already own instead of replacing it.

Schema reviews become infrastructure reviews.

Caching

TTL, scope, and revalidation behavior stay versioned with the schema, so caching policy is reviewed alongside the fields it applies to.

Invalidation

GraphPilot derives the metadata it needs to purge exactly the cache entries a write affects, without hand-maintained purge rules.

Authorization

Access rules sit close to the types and fields they protect, evaluated before an operation ever reaches origin.

Rate limiting

Reads and mutations can be capped per principal, tenant, or org so noisy traffic stays contained.

Request context

Policies can use request context such as headers, cookies, tenant IDs, or JWT claims to shape cache keys and access decisions.

Operation protection

Expensive shapes, deep nesting, and production introspection are blocked before a request can do real work.

Edge Cache

From slow.

To blazing fast.

GraphPilot turns GraphQL reads into edge-cacheable responses without changing your clients or your resolvers. The first request populates the cache. Every repeat read for the same operation and variables is served from the nearest edge location on a global network, with a sub-50ms cache-hit target.

Single POP Multiple POPs Planned new POP Planned upgrade
Map reflects the Fastly network GraphPilot deploys to, current as of June 8, 2026. Subject to change. Source: Fastly .
Fastly is a trademark of Fastly, Inc. GraphPilot is not affiliated with or endorsed by Fastly.

A cache hit returns immediately from the closest edge location. A miss is forwarded upstream and reused for matching operations and variables. The origin stays authoritative for fresh data and mutations, but repeat reads stop crossing regions: latency drops because the response is already near the client, and origin load drops because repeated query shapes no longer execute the same resolver tree.

The hard part is not storing a response. The hard part is knowing what to purge after a mutation. GraphPilot reads your schema and derives the metadata it needs for cache management automatically, so a write clears the entries it affects: the touched entities, plus the related list and aggregate results your schema policy maps to them.

Automatic cache metadata

Clients write GraphQL.

We handle the keys.

Clients keep writing ordinary GraphQL. GraphPilot derives the metadata it needs for cache management automatically, without leaking cache-management fields into Apollo, Relay, or handwritten GraphQL clients.

That keeps the invalidation contract close to the schema instead of pushing it onto every client.

It also takes a decision off the client entirely. Application developers no longer have to know what makes a response cacheable. They ask for the data they need, and the backend team owns cacheability through the schema.

query GetUser {
  user(id: "42") {
    name
  }
}

# Clients request the data they need.
# GraphPilot derives the cache metadata.
Automatic invalidation

Mutations purge

exactly what changed.

GraphPilot does not depend on hand-written purge rules. Reads become tagged cache entries; mutation responses become purge targets for the same tag model. When a user is removed, matching user reads and the list results tied to the affected keys are cleared automatically.

Cache tags stay derived from the graph instead of being maintained by hand, so a schema change updates the invalidation contract with the API shape it belongs to.

query GetUser {
  user(id: "42") {
    id
    name
  }
}

mutation {
  removeUser(id: "42") {
    id
  }
}

# The read above is cleared automatically.
Empty result caching

Empty lists count as

real cache entries.

An empty GraphQL list is still a meaningful result. GraphPilot caches that response as a first-class cache entry, instead of treating it as an uncacheable dead end.

GraphPilot handles edge cases such as empty results and list invalidation. When a write could make a previously empty list non-empty, the affected cached lists are cleared, and the next read repopulates the edge cache with the current result.

query SearchProducts {
  products(category: "new") {
    id
  }
}

mutation {
  createProduct(category: "new") {
    id
  }
}

# Empty lists stay correct after a write.
Edge Optimization

From wasteful.

To lean.

Edge caching is one lever. The bytes leaving a client travel through a chain of smaller decisions that together decide whether a response arrives in tens of milliseconds or several hundred: how many requests reach origin, how big they are on the wire, how many caches between client and edge can reuse them, how quickly the connection itself can be opened.

GraphPilot pulls those decisions to the edge and applies them by default. No SDK changes, no special headers, no per-client tuning. Eligible read traffic benefits the moment it routes through GraphPilot.

Request collapsing
A hundred clients.
One origin call.

When clients pile up on the same query at the same moment, GraphPilot collapses the duplicates and fires one request upstream. Every waiting client receives the response. Your origin sees one call.

With Origin Shielding enabled, collapsing extends across the entire network: cache misses from any edge location route through a single shield node first, so a global stampede is designed to land at origin as a single request.

Tablet
Laptop
Desktop
GraphPilot
Origin
Persisted operations
Hash over the wire.
Operation at the edge.

Once an operation is registered, clients send a short hash instead of the full query text. GraphPilot resolves the hash to the stored operation at the edge, skips parsing, and forwards a normalized request upstream.

Request bodies shrink from kilobytes to bytes, document parsing and static validation drop to a lookup, and only approved operations can ever reach the graph.

POST /graphql HTTP/2
Content-Type: application/json

{
  "extensions": {
    "persistedQuery": {
      "version": 1,
      "sha256Hash": "9f1c4a…b4e2"
    }
  },
  "variables": { "id": "42" }
}
GET-cacheable reads
One hash.
Many cache layers.

Persisted reads can travel as plain HTTP GET requests. That turns the response into something every cache between the user and the edge can store: browser caches, service workers, and shared caches deliberately placed in the path.

The fastest GraphQL request is the one that never leaves the client. The second-fastest is the one resolved by a cache that does not belong to GraphPilot at all.

GET /graphql?id=9f1c4a…b4e2&variables=%7B%22id%22%3A%2242%22%7D
Cache-Control: public, max-age=60, stale-while-revalidate=600
Vary: Accept-Encoding

# served by, in order of proximity:
#   browser HTTP cache
#   service worker
#   shared cache in the path
#   GraphPilot edge
#   origin
Edge transport
Fewer bytes.
Faster handshakes.

Every response served from GraphPilot is Brotli-compressed at the edge, typically smaller on the wire than gzip for JSON payloads. HTTP/3 over QUIC cuts much of the connection-setup tax that dominates mobile and lossy networks.

No flag to flip, no client capability to detect. GraphPilot negotiates the best transport per client and falls back gracefully when something older is on the other end.

gzip
48.2 KB
Brotli
38.6 KB
Typically smaller than gzip on JSON
HTTP/2
3 RTTs
HTTP/3
1 RTT
QUIC removes TCP + TLS negotiation
Edge Security

From exposed.

To edge-protected.

GraphQL abuse rarely looks like one loud endpoint. It can be a cheap HTTP request with an expensive selection set, a mutation loop from one account, or schema probing that should never reach production.

GraphPilot applies GraphQL-aware security controls before traffic hits your origin. Slow down abusive clients, reject untrusted requests, and block dangerous query shapes while your application stays focused on business logic.

Most of these controls start by reading something out of the request, like a tenant from a JWT claim, a region from a header, or a locale from a cookie. Policies can use that request context to derive a rate limit, a cache key, or an auth signal straight from the incoming request. A few examples are shown below.

TransmittingFREQ 001-006
Input
JWT claim · org = ACME
Signal

Normalize the tenant before it becomes part of a shared cache key.

Output
tenant: acme
Rate limiting

Control operations.

Not just requests.

A single /graphql endpoint can hide very different workloads. GraphPilot keeps traffic controls close to the graph, so operations, principals, and sensitive mutation fields can each carry their own protection model.

Cacheable reads can keep flowing while repeated mutations, scraping patterns, or one noisy organization are slowed down before resolver time is spent.

type Query {
  # cacheable reads: a generous per-tenant budget
  product(id: ID!): Product
}

type Mutation {
  # sensitive writes: a tighter per-user budget
  checkout(input: CheckoutInput!): Checkout
}
Authorize

Authorize at

the graph boundary.

GraphPilot models authorization as schema policy. Roles map to the verified identity in a request, and access rules can be attached to types and fields as well as to whole operations.

Identity providers, JWKS endpoints, and network allowlists are global deployment concerns. The schema consumes the verified identity and defines what parts of the graph it can reach.

type Customer {
  id: ID!
  # restricted to admins
  email: String!
}

type Mutation {
  # customers only
  checkout(input: CheckoutInput!): Checkout
}
Query shape protection

Block expensive

GraphQL shapes.

Some of the most expensive GraphQL requests are syntactically valid: deep nesting, alias spam, too many root fields, large variables, batched operations, or production introspection.

GraphPilot parses the operation before forwarding it and blocks dangerous or unusually expensive GraphQL shapes before they reach origin: depth limits, query-cost budgets, and production introspection blocking, with tighter ceilings for untrusted roles.

A cheap read passes untouched, while a single deeply nested or list-heavy query can blow past its budget and never reaches your origin. Anonymous traffic gets a tighter ceiling than trusted roles, so abuse is throttled without slowing the clients you trust.

# Cheap read — passes untouched.
query {
  product(id: "42") { name }
}

# Deeply nested — each level multiplies the
# work. Blocked before it reaches origin.
query {
  user(id: "42") {
    friends(first: 100) {
      friends(first: 100) {
        friends(first: 100) { name }
      }
    }
  }
}
Insights

From blind.

To informed.

Everything GraphPilot does at the edge happens out of sight. Without visibility you cannot tell whether the cache is absorbing the traffic it should, whether a security rule is acting on the right principal, or whether users in Berlin are being served from a nearby location instead of crossing the continent.

The GraphPilot portal is designed to make all of it visible by default, with nothing to instrument, no SDK to install, and no log shipping to configure. You can see where requests come from by country and edge location, which clients and user agents call each operation, how cache-hit ratios hold up per region, and where latency is best. Operations, cache health, and blocked requests each get their own view.

Portal screens below show illustrative example data.

Operation insights

Per operation.

Not per endpoint.

GraphPilot groups traffic by GraphQL operation name, not by HTTP endpoint. GetProduct, Checkout, and ListUsers each get their own row in the portal: volume, p95 latency, error rate, cache-hit ratio.

When a single mutation slows down or starts erroring, you see it immediately. A generic APM dashboard averaging everything behind POST /graphql would have hidden the signal in the noise.

Operations
Operation p95 Err Hit
GetProduct 18ms 0.02% 94%
Checkout 380ms 2.10%
ListUsers 42ms 0.10% 71%
SearchProducts 55ms 0.05% 62%
CreateOrder 95ms 0%
Cache health

Hits, misses, stales.

At a glance.

The portal shows hit, stale, and miss ratios aggregated and per operation, so you see exactly how much origin traffic the edge cache is absorbing, and where it isn't.

Every mutation lists the cache entries it invalidated. If automatic invalidation does not clear what you expect, you find out immediately, not after a stale read reaches production.

Cache
86% hit 6% stale 8% miss
Top cached
GetProduct
94%
ListUsers
71%
SearchProducts
62%
Security activity

Every block,

with the reason.

Traffic-control decisions, auth rejections, blocked query shapes. Every decision GraphPilot takes against a request is logged with the operation, the principal, and the rule that fired.

A noisy organization surfaces as a clear pattern. A spike in introspection attempts surfaces immediately. Nothing security does at the edge is silent.

Blocked requests
  1. RATE_LIMIT GetProduct org:acme 600/m exceeded
  2. AUTH Checkout anon CUSTOMER required
  3. SHAPE __schema anon introspection blocked
  4. RATE_LIMIT Checkout user:u_91f3 20/m exceeded
  5. SHAPE ListUsers anon depth > 4
GraphPilot
Founding-member perks

Pre-flight boarding is open

Reserve your seat for early access.
No credit card, no commitment, just a head start.

Get Founding Access

Join before launch to lock in founding-member perks.