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)