Persisted Documents
Persisted documents let you execute pre-registered GraphQL operations by identifier instead of sending full query text on every request.
This reduces payload size, limits arbitrary query execution, and gives you a cleaner path to queryless clients.
For the complete configuration reference, see
persisted_documents configuration.
Terminology
Different ecosystems use different names for the same pattern, including Persisted Queries, Trusted Documents, or Operation allowlisting. In Hive Router docs, we use Persisted Documents as the canonical term.
Why use persisted documents
With persisted documents enabled, clients send a document ID and Hive Router resolves the query text
from the configured storage. This reduces request payloads, blocks unregistered operations when
require_id: true, and provides a clean migration path from text queries to an allowlisted
model.
How document ID selection works
Router applies selectors in order and uses the first matching ID.
By default, if selectors is not set, Router checks documentId in the request body first (or in the query parameters if it's a GET request) and
then extensions.persistedQuery.sha256Hash (Apollo format). You can customize this order and use
json_path for custom JSON fields, url_query_param for query strings such as ?id=..., or
url_path_param for URL path segments such as /graphql/:id.
persisted_documents:
enabled: true
require_id: true
selectors:
- type: url_path_param
template: /:id # relative to the graphql endpoint, so effectivelly /graphql/:id
- type: url_query_param
name: id
storage:
type: file
path: ./persisted-documents.jsonStorrage
Hive Router supports two persisted document storage types.
File storage
File storage reads a local manifest and resolves IDs from memory. It supports both simple key-value
manifests ({ "id": "query" }) and Apollo manifest format. File watch mode is enabled by
default (watch: true), so changes are reloaded automatically, which works well with workflows
like relay-compiler --watch.
Hive CDN storage
Hive storage resolves documents from Hive CDN.
You can configure Hive credentials in router.config.yaml or with the HIVE_CDN_ENDPOINT and
HIVE_CDN_KEY environment variables.
HIVE_CDN_ENDPOINT="https://cdn.graphql-hive.com/artifacts/v1/<target_id>"
HIVE_CDN_KEY="<cdn access token>""Router accepts either full app-qualified IDs (appName~appVersion~documentId) or a plain
documentId, in which case app name and version are inferred from client identification headers.
In case you're using Apollo Client and its clientAwareness feature, please change the name and version headers to those sent by default by Apollo Client and send only plain document id:
# Client identification settings
telemetry:
client_identification:
name_header: apollographql-client-name
version_header: apollographql-client-versionID format is validated before requests are sent to CDN, so malformed IDs fail fast with clear
Rejecting requests without document id
With require_id: false (default), regular GraphQL requests (with query) are still allowed.
With require_id: true, incoming requests must provide a persisted document ID.
If you are migrating clients, log_missing_id: true helps you identify requests that still arrive without an ID.
Path selector and GraphQL endpoint compatibility
If you use url_path_param, do not use root GraphQL endpoint (http.graphql_endpoint: "/").
Root endpoint would make path matching ambiguous (for example /health could be interpreted as a
document path). Router rejects that configuration on startup.
Practical patterns
Apollo clients generally work with default selectors by sending
extensions.persistedQuery.sha256Hash. Relay-style clients typically send documentId and use a
key-value manifest. URL-driven systems can use url_path_param for path-based IDs (for example
CDN-like routes) or url_query_param for legacy query-string formats.
Troubleshooting
PERSISTED_DOCUMENT_ID_REQUIRED- failed to find a valid ID andrequire_idis enabledPERSISTED_DOCUMENT_NOT_FOUND- ID was extracted but no matching document exists in storage- Hive client identity errors: plain
documentIdwas provided without both client name and version