Working With GraphQL Caching

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or “GraphQL doesn’t care about caching.” And for most, that is a big deal.

The official GraphQL documentation refers to caching techniques so, clearly, the folks behind it do care about caching and its performance benefits.

The perception that GraphQL is at odds with caching is something I want to address in this post. I want to walk through different caching techniques and how to leverage cache for GraphQL queries.

Getting GraphQL to cache automatically

Consider the following query to fetch a post and the post author:

query getPost {
  post(slug: "working-with-graphql-caching") {
    id
    title
    author {
      id
      name
      avatar
    }
  }
}

The one “magic trick” that makes automatic GraphQL caching work is the __typename meta field that all GraphQL APIs expose.

As the name suggests, __typename returns the name of the objects type. This field can even be manually added to existing queries — and most of the time, a GraphQL client, or CDN will do it for you. urql is one such GraphQL client. The server might receive a query like this:

query getPost {
  post(slug: "working-with-graphql-caching") {
    __typename
    id
    title
    author {
      __typename
      id
      name
    }
  }
}

The response with __typename might look a little something like this:

{
  data: {
    __typename: "Post",
    id: 5,
    title: "Working with GraphQL Caching",
    author: {
      __typename: "User",
      id: 1,
      name: "Jamie Barton"
    }
  }
}

The __typename is a critical piece of the GraphQL caching puzzle because we can now cache this result, and know it contains the Post ID 5 and User ID 1.

Then there are libraries like Apollo and Relay, that also have some level of built-in caching we can use for automatic caching. Since they already know what’s in the cache, they can defer to the cache instead of remote APIs to fetch what the client asks for in a query.

Automatically invalidate the cache when there are changes

Imagine the post author edits the post’s title with the editPost mutation:

mutation {
  editPost(input: { id: 5, title: "Working with GraphQL Caching" }) {
    id
    title
  }
}

Since the GraphQL client automatically adds the __typename field, the result of this mutation immediately tells the cache that Post ID 5 has changed, and any cached query result containing that post needs to be invalidated:

{
  data: {
    __typename: "Post",
    id: 5,
    title: "Working with GraphQL Caching"
  }
}

The next time a user sends the same query, the query fetches the new data from the origin rather than serving the stale result from the cache. Magic!

Normalized GraphQL caching

Many GraphQL clients won’t cache entire query results.

Instead, they normalize the cached data into two data structures; one that associates each object with its data (e.g. Post #5: { … }, User #1: { … }, etc.); and one that associates each query with the objects it contains (e.g. getPost: { Post #5, User #1}, etc.).

See urql’s documentation on normalized caching or Apollo’s “Demystifying Cache Normalization” for specific examples and use cases.

Caching edge cases with GraphQL

The one major edge case that GraphQL caches are unable to handle automatically is adding items to a list. So, if a createPost mutation passes through the cache, it doesn’t know which specific list to add that item to.

The easiest “fix” for this is to query the parent type in the mutation if it exists. For example, in the query below, we query the community relation on post:

query getPost {
  post(slug: "working-with-graphql-caching") {
    id
    title
    author {
      id
      name
      avatar
    }

    # Also query the community of the post
    community {
      id
      name
    }
  }
}

Then we can also query that community from the createPost mutation, and invalidate any cached query results that contain that community:

mutation createPost {
  createPost(input: { ... }) {
    id
    title

    # Also query and thus invalidate the community of the post
    community {
      id
      name
    }
  }
}

While it’s imperfect, the typed schema and __typename meta field are the keys that make GraphQL APIs ideal for caching.

You might be thinking by now that all of this is a hack and that GraphQL still doesn’t support traditional caching. And you wouldn’t be wrong. Since GraphQL operates via a POST request, you’ll need to offload to the application client and use the “tricks” above to take advantage of modern browser caching with GraphQL.

That said, this sort of thing isn’t always possible to do, nor does it make a lot of sense for managing cache on the client. GraphQL clients make you manually update the cache for even trickier cases, but a service like GraphCDN provides a “server-like” caching experience, which also exposes a manual purging API that lets you do things like this for greater cache control:

# Purge all occurrences of a specific object
mutation {
  purgeUser(id: [5])
}
# Purge by query name
mutation {
  _purgeQuery(queries: [listUsers, listPosts])
}
# Purge all occurrences of a type
mutation {
  purgeUser
}

Now, no matter where you consume your GraphCDN endpoint, there’s no longer a need to re-implement cache strategies in all of your client-side logic on mobile, web, etc. Edge caching makes your API feel super fast, and reduces load by sharing the cache amongst your users, and keeping it away from each of their clients.

Having recently used GraphCDN on a project, it’s taken care of configuring a cache on the client or server for me, allowing me to get on with my project. For instance, I can swap out my endpoint with GraphCDN and obtain query complexity (which is coming soon), analytics, and more for free.


So, does GraphQL care about caching? It most certainly does! Not only does it provide some automatic caching methods baked right into it, but a number of GraphQL libraries offer additional ways to do it and even manage it.

Hopefully this article has given you some insight into the GraphQL caching story, and how to go about implementing it on the client, as well as taking advantage of CDNs to do it all for you. My goal here isn’t to sell you on using GraphQL on all your projects or anything, but if you are choosing between query languages and caching is a big concern, know that GraphQL is more than up for the task.


The post Working With GraphQL Caching appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Working With GraphQL Caching

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.