website/src/docs/hotchocolate/v12/performance/persisted-queries.md
Persisted queries allow us to pre-register all required queries of our clients. This can be done by extracting the queries of our client applications at build time and placing them in the server's query storage.
Extracting queries is supported by client libraries like Relay and in the case of Strawberry Shake we do not have to do any additional work.
<Video videoId="ZZ5PF3_P_r4" />Note: While this feature is called persisted queries it works for all other GraphQL operations as well.
Note: There are also automatic persisted queries, which allow clients to persist queries at runtime. They might be a better fit, if our API is used by many clients with different requirements.
Performance
First we have to instruct our server to handle persisted queries. We can do so by calling UsePersistedQueryPipeline() on the IRequestExecutorBuilder.
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddQueryType<Query>()
.UsePersistedQueryPipeline();
}
Hot Chocolate supports two query storages for regular persisted queries.
To load persisted queries from the filesystem, we have to add the following package.
<PackageInstallation packageName="HotChocolate.PersistedQueries.FileSystem" />After this we need to specify where the persisted queries are located. The argument of AddReadOnlyFileSystemQueryStorage() specifies the directory in which the persisted queries are stored.
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddQueryType<Query>()
.UsePersistedQueryPipeline()
.AddReadOnlyFileSystemQueryStorage("./persisted_queries");
}
When presented with a query hash, Hot Chocolate will now check the specified folder for a file in the following format: {Hash}.graphql.
Example: 0c95d31ca29272475bf837f944f4e513.graphql
This file is expected to contain the query the hash was generated from.
Warning: Do not forget to ensure that the server has access to the directory.
To load persisted queries from Redis, we have to add the following package.
<PackageInstallation packageName="HotChocolate.PersistedQueries.Redis" />After this we need to specify where the persisted queries are located. Using AddReadOnlyRedisQueryStorage() we can point to a specific Redis database in which the persisted queries are stored.
public void ConfigureServices(IServiceCollection services)
{
services
.AddGraphQLServer()
.AddQueryType<Query>()
.UsePersistedQueryPipeline()
.AddReadOnlyRedisQueryStorage(services =>
ConnectionMultiplexer.Connect("host:port").GetDatabase());
}
Keys in the specified Redis database are expected to be a query id (hash) and contain the actual query as the value.
Per default Hot Chocolate uses the MD5 hashing algorithm, but we can override this default by specifying a DocumentHashProvider.
public void ConfigureServices(IServiceCollection services)
{
services
// choose one of the following providers
.AddMD5DocumentHashProvider()
.AddSha256DocumentHashProvider()
.AddSha1DocumentHashProvider()
// GraphQL server configuration
.AddGraphQLServer()
.AddQueryType<Query>()
.UsePersistedQueryPipeline()
.AddReadOnlyFileSystemQueryStorage("./persisted_queries");
}
We can also configure how these hashes are encoded, by specifying a HashFormat as argument:
AddSha256DocumentHashProvider(HashFormat.Hex)
AddSha256DocumentHashProvider(HashFormat.Base64)
Note: Relay uses the MD5 hashing algorithm - no additional Hot Chocolate configuration is required.
A client is expected to send an id field containing the query hash instead of a query field.
HTTP POST
{
"id": "0c95d31ca29272475bf837f944f4e513",
"variables": {
// ...
}
}
Note: Relay's persisted queries documentation uses
doc_idinstead ofid, be sure to change it toid.