GraphQL Persisted Queries: Speed Up Your API by Orders of Magnitude
We frequently encounter a situation: a client application sends enormous GraphQL queries (e.g., query { user { posts { comments { author { ... } } } } }) weighing 10–15 KB. Over mobile networks, this results in a TTFB of 3–5 seconds. Persisted Queries solve this radically: instead of the full query body, the client sends only a SHA256 hash (44 bytes). The server (or CDN) returns a cached response. This reduces traffic by 60% and enables HTTP-level caching. According to Apollo, APQ cut request size by 20x for repeated calls.
Our experience: over the last few years we have implemented this technique in 30+ projects. In one case (an e-commerce site with a million products), APQ reduced request size from 8 KB to 400 bytes, and LCP dropped from 3.2s to 1.1s. We guarantee a clean implementation without security trade-offs.
How Automatic Persisted Queries (APQ) Work
APQ is a two-phase protocol. The client first sends a POST request with only the hash. If the server cache does not contain the query, it returns 404. Then the client retries with the full query body. The server saves the hash→query pair and returns data. All subsequent calls are just the hash, and you can switch to GET requests that are cached on the CDN.
Client Server CDN/Cache │ │ │ │ POST {hash} │ │ │───────────────>│ │ │ 404 Not Found │ │ │<───────────────│ │ │ │ │ │ POST {hash + query body} │ │───────────────>│ │ │ {data} [store hash→query] │ │<───────────────│ │ │ │ │ │ GET ?hash=... │ │ │──────────────────────────────> │ │ {data} from cache │ │<────────────────────────────── │ Comparison: APQ vs Registered PQ vs No PQ
| Criterion | Without Persisted Queries | APQ | Registered PQ |
|---|---|---|---|
| Request size | Full (up to 15 KB) | Hash (44 bytes) + occasionally full | Only hash |
| CDN caching | Only if idempotent | GET requests cached | GET requests cached |
| Security | Any query | Any query after registration | Only registered queries |
| Implementation effort | — | Low (1–2 days) | Medium (3–5 days) |
Optimizing GraphQL queries with Persisted Queries boosts API performance and improves Core Web Vitals.
Order Persisted Queries implementation — we'll show metrics before and after on a test bench.
Why Use Registered Persisted Queries?
Registered Persisted Queries (RPQ) are APQ + a whitelist. In production, only queries whose hashes appear in a manifest are allowed. This eliminates attacks via __schema or arbitrary mutations. The manifest is generated from client code at build time.
# Generate manifest from client operations npx generate-persisted-query-manifest \ --documents "src/**/*.graphql" \ --output persisted-query-manifest.json // persisted-query-manifest.json (fragment) { "format": "apollo-persisted-query-manifest", "version": 1, "operations": [ { "id": "dc67510fb4289672bea757e862d6b00e...", "name": "GetPosts", "type": "query", "body": "query GetPosts($limit: Int) { posts(first: $limit) { ... } }" } ] } On the server, you only need middleware that substitutes the query body from the manifest and rejects unknown hashes.
Real case: RPQ for a fintech application
In a project with high security requirements (payment processing), we implemented RPQ. We generated a manifest of 120 operations and set up strict control. The result: zero incidents in six months, TTFB reduced by 40% thanks to GET caching on Cloudflare. Infrastructure cost savings amounted to 30%.Typical Problems and Their Solutions
| Problem | Solution |
|---|---|
| Cache staleness on schema change | Use Redis with TTL of 24 hours and invalidate by schema version |
| Lack of APQ support in library | Implement middleware: check incoming JSON for extensions.persistedQuery |
| Slow manifest generation in CI | Incremental build: save previous manifest and update only changed files |
How We Implement Persisted Queries: Step by Step
- Audit current GraphQL API: analyze request sizes, duplicate frequency, existing caching.
- Design: choose approach (APQ or RPQ), define TTL, configure Redis for distributed cache.
- Client implementation: integrate
createPersistedQueryLinkin Apollo Client or equivalent for Relay/Urql. - Server implementation: enable APQ (built into Apollo Server), configure cache, add middleware for RPQ if needed.
- Testing: verify caching correctness, monitor hit rates.
- Deploy and CDN: configure Nginx for GET caching, enable Cloudflare or Vercel Edge.
What Is Included
- Documentation of schema and manifest.
- Setup of cache monitoring (Prometheus/Grafana).
- Team training on maintenance and manifest updates.
- Post-release support for 2 weeks.
- Handover of repository and documentation.
We use proven configurations. Example Nginx setup:
proxy_cache_path /var/cache/nginx/graphql levels=1:2 keys_zone=graphql:10m max_size=100m inactive=1h use_temp_path=off; location /graphql { if ($request_method = GET) { proxy_cache graphql; proxy_cache_key "$uri$is_args$args"; proxy_cache_valid 200 5m; proxy_cache_use_stale error timeout updating; add_header X-Cache-Status $upstream_cache_status; } proxy_pass http://api_backend; } Timeline and Cost
Basic APQ setup with Redis and CDN — 1 to 2 business days. Full cycle with Registered Persisted Queries, manifest, and monitoring — 3 to 5 days. Cost is calculated individually based on schema complexity and number of clients.
Accelerate your GraphQL API — contact us for a project evaluation. We'll show metrics before and after on a test bench.







