For as long as most of us have been building web APIs, there's been an awkward gap in HTTP's method vocabulary. You want to ask a server a question — run a search, filter a dataset, evaluate a complex query — and get an answer back without changing anything. HTTP has never had a clean way to do that. As of RFC 10008, published in June 2026, it finally does: the QUERY method.
This post explains the problem QUERY solves, what makes it different from GET and POST, and the one genuinely tricky part — caching.
The problem: GET and POST both fit badly
When you need to send a query to a server, you've historically had two bad options.
Use GET. GET is the natural fit semantically: it's safe (it doesn't change server state) and idempotent (making the same request twice has the same effect as making it once), and its responses are cacheable. The problem is that GET carries its parameters in the URL. That's fine for ?page=2&sort=name, but it falls apart the moment your query is large or structured. URLs have length limits (proxies, servers, and browsers all impose their own), you have to URL-encode everything, and expressing a nested JSON filter or a GraphQL-style query as query-string parameters ranges from ugly to impossible. Sending a request body with GET is technically undefined and widely ignored, so that door is closed.
Use POST. POST lets you put a rich, structured query in the request body with whatever media type you like — JSON, GraphQL, SQL-ish DSLs, protobuf, anything. That's why virtually every search and GraphQL endpoint uses POST today. But POST is semantically wrong for a read. POST is neither safe nor idempotent: to HTTP, caches, and intermediaries, a POST looks like it might create or change something. So responses generally aren't cached, clients won't automatically retry a failed POST (it might have side effects), and you lose all the machinery that makes reads on the web fast and resilient.
So for decades we've been picking between "correct semantics but can't send real data" (GET) and "can send real data but wrong semantics" (POST). QUERY exists to end that compromise.
What QUERY actually is
QUERY is, in the words of the spec, a method that requests the target process the enclosed content and respond with the result of that processing. In plainer terms: it's a request that carries a body like POST, but is declared safe and idempotent like GET.
Three properties define it:
It is safe — a QUERY does not alter the state of the resource it targets. It's a read, and clients, servers, and intermediaries can treat it as one.
It is idempotent — repeating the same QUERY has the same effect as sending it once. Because there's no partial state change to worry about, a QUERY can be safely retried or restarted automatically, for example after a dropped connection. This is the key thing POST can never offer.
It is cacheable — responses can be stored and reused, which brings the performance benefits of GET to requests that were previously stuck as uncacheable POSTs.
The request body carries the query itself, and its media type describes what kind of query it is. The server processes that content and returns the result. This is exactly the shape that search endpoints, GraphQL, analytics APIs, and complex filtering have always wanted: a real body, plus honest read semantics.
QUERY vs GET vs POST at a glance
| Property | GET | POST | QUERY |
|---|---|---|---|
| Carries a request body | No (undefined) | Yes | Yes |
| Safe (no state change) | Yes | No | Yes |
| Idempotent (safe to retry) | Yes | No | Yes |
| Cacheable | Yes | Rarely | Yes |
| Good for large/structured queries | No | Yes | Yes |
QUERY is essentially the cell that was always missing: the safe, idempotent, cacheable method that can still carry a body.
The catch: caching is harder than it looks
The headline feature — cacheable queries with a body — is also where the real engineering complexity lives, and it's worth being honest about it.
With GET, the cache key is basically the URL. It's short, it's right there in the request line, and a cache can decide what to do before reading anything else. QUERY breaks that convenience. Because the meaningful part of the request now lives in the body, a cache has to read the entire request content to compute the cache key. That's fundamentally more work than keying on a URL.
Worse, bodies aren't naturally canonical. Two JSON queries that are semantically identical — same fields, different whitespace or key ordering — are different byte sequences, and a naïve cache would treat them as different keys, tanking the hit rate. So effective QUERY caching depends on normalizing the request body before keying on it, which pushes real complexity into caches and intermediaries. The spec also provides mechanisms for a server to point at a cacheable representation of the results (so that follow-up reads can behave more like ordinary GETs), but the underlying reality remains: caching a QUERY is materially more involved than caching a GET.
None of this makes QUERY worse than the POST-based status quo — POST responses usually weren't cached at all. It just means the caching win isn't free; it arrives with new requirements for the infrastructure in the middle.
Should you use it yet?
QUERY is now a published standard (RFC 10008), which is the milestone that lets client libraries, servers, frameworks, proxies, and CDNs begin implementing it with confidence. But "standardized" and "universally deployed" are not the same thing. Real-world adoption depends on the whole chain — HTTP clients, server frameworks, load balancers, API gateways, and caches — understanding the method. Until that support is broad, a QUERY request may be rejected or mishandled by some intermediary that's never heard of it, and you'll still see POST used as the pragmatic fallback for a while.
The sensible read for now: QUERY is the correct answer to a problem the industry has worked around for thirty years, and it's finally a real standard rather than a proposal. If you build APIs where reads carry heavy or structured payloads — search, GraphQL, analytics, complex filtering — it's worth understanding now and adopting as your stack's support catches up. It won't replace GET for simple reads or POST for genuine writes; it fills the specific, long-standing gap between them.
Sources: RFC 10008: The HTTP QUERY Method (RFC Editor), RFC 10008 (IETF Datatracker), draft-ietf-httpbis-safe-method-w-body (IETF Datatracker), RFC 10008: The New HTTP QUERY Method Explained (Developers Digest)
Top comments (0)