Persisted Documents
Persisted documents let clients run pre-registered GraphQL operations by ID, without sending the full query text on every request.
This reduces payload size, limits arbitrary query execution, and helps you move 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
When persisted documents are enabled, clients send a document ID. Hive Router then loads the query
text from configured storage. This reduces request payloads, blocks unregistered operations when
require_id: true, and gives you a clear migration path from text queries to an allowlist model.
How document ID selection works
Router applies selectors in order and uses the first matching ID.
If you do not set selectors, Router first checks documentId (request body for POST, query
parameter for GET), 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 effectively /graphql/:id
- type: url_query_param
name: id
storage:
type: file
path: ./persisted-documents.jsonStorage
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.
If you use Apollo Client clientAwareness or Apollo Kotlin client awareness, set the name and version headers to Apollo's default header names, then send only a 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 errors.
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.
During migration, log_missing_id: true helps you find 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: "/").
At the root endpoint, path matching is 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- no valid ID was extracted - check selector order and where the request sends the IDPERSISTED_DOCUMENT_NOT_FOUND- ID was extracted but no matching document exists in storage; verify the ID exists in the manifest or CDN- Hive client identity errors - plain
document IDwas provided without both client name and version - set client identification headers or send an app-qualified ID