Apollo Kotlin Normalized Cache Help

Expiration

The cache can be configured to store expiration information using a max-age. This is also sometimes referred to as TTL (Time To Live) or freshness.

Max-age can be configured by the server, by the client, or both.

Server-controlled max-age

When receiving a response from the server, the Cache-Control HTTP header can be used to determine the max age of the fields in the response.

The cache can be configured to store the expiration date of the received fields in the corresponding records. To do so, call .storeExpirationDate(true), and set your client's cache resolver to CacheControlCacheResolver:

val apolloClient = ApolloClient.builder() .serverUrl("https://example.com/graphql") .storeExpirationDate(true) .normalizedCache( normalizedCacheFactory = /*...*/, cacheResolver = CacheControlCacheResolver(), ) .build()

Expiration dates are stored and when a field is resolved, the cache resolver will check if the field is stale. If so, it will return an error..

Client-controlled max-age

When storing fields, the cache can also store their received date. This date can then be compared to the current date when resolving a field to determine if its age is above its max age.

To store the received date of fields, call .storeReceivedDate(true), and set your client's cache resolver to CacheControlCacheResolver:

val apolloClient = ApolloClient.builder() .serverUrl("https://example.com/graphql") .storeReceivedDate(true) .normalizedCache( normalizedCacheFactory = /*...*/, cacheResolver = CacheControlCacheResolver(maxAgeProvider), ) .build()

The max age of fields can be configured either programmatically, or declaratively in the schema. This is done by passing a MaxAgeProvider to the CacheControlCacheResolver.

Global max age

To set a global maximum age for all fields, pass a GlobalMaxAgeProvider to the CacheControlCacheResolver:

cacheResolver = CacheControlCacheResolver(GlobalMaxAgeProvider(1.hours)),

Max age per type and field

Programmatically

Use a SchemaCoordinatesMaxAgeProvider to specify a max age per type and/or field:

cacheResolver = CacheControlCacheResolver( SchemaCoordinatesMaxAgeProvider( maxAges = mapOf( "Query.cachedBook" to MaxAge.Duration(60.seconds), "Query.reader" to MaxAge.Duration(40.seconds), "Post" to MaxAge.Duration(4.minutes), "Book.cachedTitle" to MaxAge.Duration(30.seconds), "Reader.book" to MaxAge.Inherit, ), defaultMaxAge = 1.hours, ) ),

Note that this provider replicates the behavior of Apollo Server's @cacheControl directive when it comes to defaults and the meaning of Inherit.

Declaratively

To declare the maximum age of types and fields in the schema, use the @cacheControl and @cacheControlField directive:

# First import the directives extend schema @link( url: "https://specs.apollo.dev/cache/v0.3", import: ["@cacheControl", "@cacheControlField"] ) # Then extend your types extend type Query @cacheControl(maxAge: 60) @cacheControlField(name: "cachedBook", maxAge: 60) @cacheControlField(name: "reader", maxAge: 40) extend type Post @cacheControl(maxAge: 240) extend type Book @cacheControlField(name: "cachedTitle", maxAge: 30) extend type Reader @cacheControlField(name: "book", inheritMaxAge: true)

This generates a map in yourpackage.cache.Cache.maxAges, that you can pass to the SchemaCoordinatesMaxAgeProvider:

cacheResolver = CacheControlCacheResolver( SchemaCoordinatesMaxAgeProvider( maxAges = Cache.maxAges, defaultMaxAge = 1.hours, ) )
Last modified: 09 October 2025