<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky" -->

---
title: Does GraphQL break HTTP caching? Here's what POST gives up.
description: A conventional POST /graphql endpoint gives up the URL-based cache key that CDNs and shared caches rely on. HTTP's cache key is built from the request method...
canonical: https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Does GraphQL break HTTP caching? Here's what POST gives up. | daily.dev
og:description: A conventional POST /graphql endpoint gives up the URL-based cache key that CDNs and shared caches rely on. HTTP's cache key is built from the request method...
og:url: https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky
og:image: https://api.daily.dev/og/posts/P5cRgbFkY.png
og:image:alt: Does GraphQL break HTTP caching? Here's what POST gives up.
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Does GraphQL break HTTP caching? Here's what POST gives up.

**[WunderGraph](https://daily.dev/sources/wundergraph)** · 17 min read · 0 upvotes · 0 comments

## Summary

A conventional POST /graphql endpoint gives up the URL-based cache key that CDNs and shared caches rely on. HTTP's cache key is built from the request method and target URI at minimum, so a POST body with operations and variables never factors in. Sending queries over GET restores a cacheable shape, and swapping the full query text for a persisted document hash keeps those URLs short. URL length limits still apply: nginx defaults to an 8KB request line, Apache to 8190 bytes, CloudFront to 8,192 bytes, while Chrome documents a 2MB limit. Build-time persisted documents (a safelist) and Automatic Persisted Queries are different mechanisms and shouldn't be conflated. Viewer-specific data must still be kept out of shared caches.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://wundergraph.com/blog/graphql-http-caching>

## Questions this post answers

### why doesn't my CDN cache GraphQL POST requests to /graphql

HTTP caches build their cache key from the request method and target URI at minimum, and a GraphQL POST puts the operation and variables in the request body, which is not part of that key. Every request to /graphql looks identical to the cache, so it gets passed through to the origin. RFC 9111 also requires a non-error response to a POST to invalidate stored responses for that target URI.

_If you're trying to get GraphQL responses cached at the edge, daily.dev surfaces write-ups like this on CDN caching strategy._

### does CloudFront, Cloudflare, or Fastly cache POST responses by default

Not by default for any of them. CloudFront caches GET, HEAD, and optionally OPTIONS, and does not cache other methods at all. Cloudflare's documented non-caching condition is any method other than GET, and it doesn't cache JSON by default even over GET. Fastly passes through everything except GET, HEAD, and PURGE, though req.body (for bodies under 8KB) is available in VCL to build a custom cache key. Akamai is the exception, offering a supported Cache POST Responses feature limited to 16KB requests plus a GraphQL-specific behavior that skips analysis above 4096-byte queries.

_Comparing CDN caching behavior across vendors is easier when engineers share findings like this on daily.dev._

### what's the difference between automatic persisted queries and a GraphQL safelist

Automatic Persisted Queries (APQ) register operations at runtime: the client sends a hash, the server returns a not-found error if it's unknown, the client retries with the full document, and the server caches the mapping, after which requests can be hash-only GETs. A safelist, or build-time persisted document list, is registered ahead of time from source code at build time, and once enforced, the server executes only what's in that manifest. Cosmo's docs state its safelist option cannot run alongside APQ because their functions are opposite.

_Teams deciding between APQ and a safelist for GraphQL security can track these distinctions on daily.dev._

## Similar posts on daily.dev

- [Resolving the HTTP Compromise: A Pragmatic Look at the New QUERY Method](https://daily.dev/posts/resolving-the-http-compromise-a-pragmatic-look-at-the-new-query-method-venauqneb) · Medium · 5 upvotes · 0 comments
- [HTTP gets a QUERY method so complex searches can stop pretending to be POST](https://daily.dev/posts/http-gets-a-query-method-so-complex-searches-can-stop-pretending-to-be-post-mk7367aia) · DEVCLASS · 294 upvotes · 11 comments
- [Why HTTP needed a new method after 30 years - meet QUERY](https://daily.dev/posts/why-http-needed-a-new-method-after-30-years---meet-query-a5uhffgpn) · Medium · 12 upvotes · 1 comments
- [RFC 10008: The HTTP QUERY Method](https://daily.dev/posts/rfc-10008-the-http-query-method-4azpxbmjt) · Blain Smith · 18 upvotes · 0 comments

---

Tags: [#graphql](https://daily.dev/tags/graphql), [#rest-api](https://daily.dev/tags/rest-api)

[View this post on daily.dev](https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Does GraphQL break HTTP caching? Here's what POST gives up.","url":"https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky"},"datePublished":"2026-10-28T21:22:21.975Z","dateModified":"2026-10-28T21:34:56.576Z","description":"A conventional POST /graphql endpoint gives up the URL-based cache key that CDNs and shared caches rely on. HTTP's cache key is built from the request method...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/0a4bd771934b4193255cbb81d4d22d29?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/0a4bd771934b4193255cbb81d4d22d29?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"WunderGraph","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"WunderGraph","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1681654408/logos/WunderGraphs","url":"https://daily.dev/sources/wundergraph"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"graphql,rest-api","timeRequired":"PT17M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"WunderGraph","item":"https://daily.dev/sources/wundergraph"},{"@type":"ListItem","position":3,"name":"Does GraphQL break HTTP caching? Here's what POST gives up."}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/does-graphql-break-http-caching-here-s-what-post-gives-up--p5crgbfky#faq","mainEntity":[{"@type":"Question","name":"why doesn't my CDN cache GraphQL POST requests to /graphql","acceptedAnswer":{"@type":"Answer","text":"HTTP caches build their cache key from the request method and target URI at minimum, and a GraphQL POST puts the operation and variables in the request body, which is not part of that key. Every request to /graphql looks identical to the cache, so it gets passed through to the origin. RFC 9111 also requires a non-error response to a POST to invalidate stored responses for that target URI. If you're trying to get GraphQL responses cached at the edge, daily.dev surfaces write-ups like this on CDN caching strategy."}},{"@type":"Question","name":"does CloudFront, Cloudflare, or Fastly cache POST responses by default","acceptedAnswer":{"@type":"Answer","text":"Not by default for any of them. CloudFront caches GET, HEAD, and optionally OPTIONS, and does not cache other methods at all. Cloudflare's documented non-caching condition is any method other than GET, and it doesn't cache JSON by default even over GET. Fastly passes through everything except GET, HEAD, and PURGE, though req.body (for bodies under 8KB) is available in VCL to build a custom cache key. Akamai is the exception, offering a supported Cache POST Responses feature limited to 16KB requests plus a GraphQL-specific behavior that skips analysis above 4096-byte queries. Comparing CDN caching behavior across vendors is easier when engineers share findings like this on daily.dev."}},{"@type":"Question","name":"what's the difference between automatic persisted queries and a GraphQL safelist","acceptedAnswer":{"@type":"Answer","text":"Automatic Persisted Queries (APQ) register operations at runtime: the client sends a hash, the server returns a not-found error if it's unknown, the client retries with the full document, and the server caches the mapping, after which requests can be hash-only GETs. A safelist, or build-time persisted document list, is registered ahead of time from source code at build time, and once enforced, the server executes only what's in that manifest. Cosmo's docs state its safelist option cannot run alongside APQ because their functions are opposite. Teams deciding between APQ and a safelist for GraphQL security can track these distinctions on daily.dev."}}]}
```

