DEV Community

Cover image for ๐Ÿš€ Speed Up Your GraphQL Requests with Automatic Persisted Queries (APQ)
0x4
0x4

Posted on

๐Ÿš€ Speed Up Your GraphQL Requests with Automatic Persisted Queries (APQ)

If you're using GraphQL in production, you've probably heard about Automatic Persisted Queries (APQ). But what are they exactly, and why should you care?

In this post, weโ€™ll walk through:

  • Why GET requests can improve GraphQL performance
  • What APQ is and how it works
  • How to implement APQ (with code!)
  • How the client knows when to send only the hash
  • How to handle fallbacks gracefully

๐Ÿ“ฆ Why Use GET Requests in GraphQL?

GraphQL usually uses POST requests for sending queries. However, when the operation is a read (query), using GET has a huge benefit: HTTP caching via browsers, proxies, or CDNs.

But thereโ€™s a catch: GET requests pass the query in the URL, and URLs have size limits. So for large or complex queries, it can break.


๐Ÿง  Enter: Automatic Persisted Queries (APQ)

Instead of sending the full query in the URL or request body, you just send a hash of the query. The server:

  • Checks if it already knows this query
  • If yes, executes it and returns the result
  • If not, returns a PersistedQueryNotFound error
  • The client then retries, this time with the full query and the hash

This avoids sending the full query every time and enables GET requests with tiny URLs.


๐Ÿ” APQ Lifecycle Example

Hereโ€™s what happens step-by-step:

1. First Request (GET):

GET /graphql?extensions={
  "persistedQuery": {
    "version": 1,
    "sha256Hash": "abcd1234..."
  }
}&operationName=GetUser
Enter fullscreen mode Exit fullscreen mode

2. Server Response:

{
  "errors": [
    {
      "message": "PersistedQueryNotFound"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3. Client Retry (POST):

{
  "query": "query GetUser { user { id name } }",
  "extensions": {
    "persistedQuery": {
      "version": 1,
      "sha256Hash": "abcd1234..."
    }
  },
  "operationName": "GetUser"
}
Enter fullscreen mode Exit fullscreen mode

4. Server stores the query and executes it. โœ…

On the next identical request, the client only sends the hash!


โš™๏ธ How Does the Client Know?

Most GraphQL clients (Apollo, urql) handle APQ automatically. You donโ€™t need to write extra logic โ€” just enable it in the config.

Example with Apollo Client:

import { createPersistedQueryLink } from "@apollo/client/link/persisted-queries";
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { sha256 } from "crypto-hash";

const link = createPersistedQueryLink({ sha256 }).concat(
  new HttpLink({ uri: "/graphql" })
);

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link
});
Enter fullscreen mode Exit fullscreen mode

Apollo will:

  • First send a hash via GET
  • Retry with full query via POST if not found

๐Ÿ”ฅ Bonus: Benefits of Using APQ

  • Smaller payloads
  • Easier CDN caching
  • Increased performance for mobile clients
  • Optional: block non-whitelisted queries in production

๐Ÿงฏ What If the First Request Fails?

If the server responds with PersistedQueryNotFound, the client automatically retries with the full query โ€” the user never sees the failure.

Still, for better DX, you can catch and track these retries for debugging or analytics.


Thatโ€™s it! APQ is a clever pattern to boost performance and reduce bandwidth โ€” and itโ€™s surprisingly simple to adopt.

๐Ÿง  Have questions or tips? Let me know in the comments!

Top comments (0)