How to Use Persisted Queries in GraphQL for Faster Requests
Persisted queries in GraphQL let you send a small query ID instead of the full query text by storing queries on the server beforehand. Use
apollo-server or similar tools to register queries and clients send only the query hash, reducing bandwidth and improving speed.Syntax
Persisted queries use a queryId or hash to identify a stored query on the server. The client sends this ID instead of the full query text. The server looks up the query by ID and executes it.
Key parts:
queryId: Unique identifier for the stored query.extensions.persistedQuery.sha256Hash: The hash sent by the client to identify the query.GET or POST request: The client sends the ID in the request instead of the full query.
http
POST /graphql HTTP/1.1 Host: example.com Content-Type: application/json { "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "<query_hash_here>" } }, "variables": {} }
Example
This example shows how to set up Apollo Server with persisted queries and how a client sends a query hash instead of the full query.
javascript
// Server setup with Apollo Server and Apollo Persisted Queries const { ApolloServer, gql } = require('apollo-server'); const crypto = require('crypto'); // Sample schema const typeDefs = gql` type Query { hello: String } `; const resolvers = { Query: { hello: () => 'Hello world!' } }; // Store queries with their hashes const storedQueries = new Map(); // Example query const query = `query { hello }`; const hash = crypto.createHash('sha256').update(query).digest('hex'); storedQueries.set(hash, query); // Apollo Server with persisted query support const server = new ApolloServer({ typeDefs, resolvers, plugins: [{ requestDidStart() { return { async didResolveOperation({ request }) { const hash = request.extensions?.persistedQuery?.sha256Hash; if (hash && !request.query) { request.query = storedQueries.get(hash); } } }; } }] }); server.listen().then(({ url }) => { console.log(`Server ready at ${url}`); }); // Client sends only the hash: // { // "extensions": { // "persistedQuery": { // "version": 1, // "sha256Hash": "<hash>" // } // }, // "variables": {} // }
Output
Server ready at http://localhost:4000/
Common Pitfalls
Common mistakes when using persisted queries include:
- Not storing the query on the server before the client sends the hash, causing errors.
- Clients sending hashes that the server does not recognize.
- Forgetting to handle the case when the query text is missing and only the hash is sent.
- Not versioning persisted queries, which can cause cache mismatches.
Always ensure the server has the query stored and can resolve the hash before executing.
json
// Wrong: Client sends hash but server has no stored query { "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "unknownhash" } }, "variables": {} } // Right: Server stores query and client sends matching hash // Server stores: 'query { hello }' with hash 'abc123' // Client sends: { "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "abc123" } }, "variables": {} }
Quick Reference
Tips for using persisted queries:
- Generate a SHA-256 hash of your GraphQL query.
- Store the query and hash on the server before clients use it.
- Clients send only the hash in the
extensions.persistedQuery.sha256Hashfield. - Handle missing queries gracefully by falling back to full query if needed.
- Use versioning to manage query updates.
Key Takeaways
Persisted queries reduce bandwidth by sending only query hashes instead of full queries.
Always store queries on the server with their hashes before clients send requests.
Clients must send the correct SHA-256 hash in the request extensions to identify queries.
Handle missing or unknown hashes on the server to avoid errors.
Version persisted queries to manage updates and cache consistency.