Reduce GraphQL Request Size with Apollo Persisted Queries
Apollo persisted queries send an operation ID instead of the full GraphQL document, shrinking request payloads and enabling server-side plan reuse.
10 Feb 2026, 01:43 UTC

Problem: GraphQL requests carry the full document every time
When a web or mobile client sends a GraphQL operation, the HTTP body usually includes the complete query or mutation string. If the operation selects many nested fields, that string can grow to several kilobytes. On metered connections or high-traffic APIs, repeatedly sending the same document wastes bandwidth and adds latency before the server can even begin resolving data.
Thesis: persisted queries replace the document with an identifier
Apollo’s persisted query feature lets a server store a parsed query plan associated with an operation identifier. After registration, the client sends only that identifier and the variable values instead of the full GraphQL document. The server looks up the cached plan and executes it without re-parsing the request string.
How persisted queries work
The process has two phases. First, during build or deployment, each client operation is registered with the Apollo server. The server computes an identifier, often a hash of the query document, and stores the parsed document in memory. Second, at runtime, the client sends a small JSON payload containing the identifier and variables. The server matches the identifier to the stored plan, skips parsing and validation for that operation, and proceeds directly to execution.
This behavior depends on the Apollo Server version and client library. In Apollo Server 4.x, persisted queries are configured through server options and plugins; check the documentation for your exact version before adapting the example below.
Worked example: configuration flow
The following example illustrates the general shape of the setup. It is not a copy-paste production implementation; adapt the package names and APIs to your Apollo Server version.
// Illustrative server setup (conceptual)
const server = new ApolloServer({
schema,
persistedQueries: {
// Enable lookup by operation ID
// Implementation varies by Apollo Server version
}
});
// Illustrative client request (conceptual)
fetch('/graphql', {
method: 'POST',
body: JSON.stringify({
operationId: 'a1b2c3d4',
variables: { userId: '123' }
})
});
Where to run: the server snippet runs in the Node.js process that hosts your GraphQL endpoint. The client snippet runs in the browser or mobile application that calls the endpoint. Required permissions: the server process must be able to bind to its configured port and read the registered query store; the client needs network access to the GraphQL URL.
Expected check: open your browser’s network inspector, trigger the operation, and compare the request body size against the raw GraphQL document. The persisted request should contain only the identifier and variables, typically tens of bytes instead of hundreds or thousands.
Trade-off: queries must be pre-registered
The main limitation is that the server cannot execute an operation it has not registered. Dynamic queries built by users, ad-hoc queries from debugging tools, or client-side generated fragments will fail unless the deployment pipeline registers them first. This adds a build-time step: your CI process must extract operations from the client bundle and upload them to the server before the new client version is released.
If a client sends an unregistered identifier, the server returns an error rather than executing the operation. Clients should handle this explicitly instead of treating a missing plan as a silent network failure.
Practical verification
- Register one operation in your staging server.
- Configure the client to send the operation ID for that operation only.
- Capture the request in the network inspector and confirm the body no longer contains the GraphQL document string.
- Confirm the server returns the same data as the unpersisted version.
If the sizes do not shrink, check that the client is actually sending the identifier and that the server has persisted queries enabled. If the server returns errors for known operations, verify that the registration step completed successfully in the deployment pipeline.
Actionable closing
Start with a single, high-traffic query rather than converting every operation at once. Register it in staging, switch the client to send the operation ID, and measure the request size. Once that works, add the registration step to your CI pipeline and expand to additional operations. Persisted queries are most valuable when the same operation is repeated frequently with different variables.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.