The HTTP QUERY method (RFC 10008, June 2026) is a new REST request method that is safe and idempotent like GET but carries the query in a request body like POST — so large, structured queries finally get HTTP-layer caching and automatic retries. It's the first general-purpose method HTTP has gained since PATCH in 2010, and it closes a design gap REST API developers have been working around for 25 years. If you've ever tunneled a read-only search through POST and silently given up caching and retry safety, this method exists because of you.
TL;DR
- QUERY is a new HTTP request method that sends a query in the request body while guaranteeing the operation is safe and idempotent — no state change, freely retryable, and cacheable by proxies and CDNs.
- It exists because GET can't reliably carry a body (the spec gives GET bodies "no defined semantics", and URLs cap out around 2,000–8,000 characters) while POST forfeits caching and automatic retries even for purely read-only queries.
- The cache key for a QUERY request is the URL plus the request body, so two identical searches can be served from the edge without touching your origin — something POST-based search endpoints will never get.
- It's already real: Node.js parses QUERY natively (21.7.2+/22+), Fastify supports it via
addHttpMethod(), nginx landed basic support, ASP.NET Core recognizes it in .NET 11 previews, and OpenAPI 3.2 models it — but browsers'fetch()can't send it yet. -
My take: design new server-to-server search/filter/report endpoints as QUERY-shaped now (single query document in the body, mandatory
Content-Type), even if you expose them via POST today. The migration later becomes a method-name change.
What Is the HTTP QUERY Method?
The HTTP QUERY method is a safe, idempotent request method, defined in RFC 10008, that asks a resource to run a query described by the request body and return the result. The body — with a mandatory Content-Type — carries the query parameters, so the URL no longer has to. Unlike POST, the server promises the operation changes nothing; unlike GET, the query can be as large and structured as you want: JSON documents, GraphQL queries, SQL-ish filters, JSONPath expressions.
The RFC's own framing is precise: a QUERY request asks "the target resource to perform a query operation within the scope of that target resource." Two guarantees make everything else possible. First, safety: "the client does not request or expect any change to the state of the target resource." Second, idempotency: QUERY requests "can be retried or repeated when needed, for instance, after a connection failure."
That second sentence is the quiet superpower. A dropped connection mid-POST leaves your client guessing — did the server process it? A dropped connection mid-QUERY is a non-event: any client, library, or proxy may resend it without asking.
Why HTTP Needed a New Method
Here's the design flaw we all normalized: HTTP made you choose between honest semantics and a request body.
GET is the semantically correct method for reads. Every cache, proxy, prefetcher, and crawler on Earth understands it. But RFC 9110 gives content in a GET request "no generally defined semantics" — intermediaries may drop it, some servers reject it, and browsers won't send it. So real query data had to squeeze into the URL, which breaks somewhere between 2,000 and 8,000 characters depending on the browser, proxy, and server in the chain.
POST takes any body you like. But POST is defined as potentially unsafe and non-idempotent, so every intermediary treats your read-only search like a payment submission: no shared caching, no automatic retry, no prefetching. Every GraphQL query — explicitly read-only by design — loses HTTP-level caching and retry safety the moment it ships as POST.
The industry's workarounds tell the story better than any spec rationale:
This isn't a new idea, which makes the 18-year journey instructive. WebDAV had a body-carrying SEARCH method back in RFC 5323 (2008), but it never escaped WebDAV's orbit. The IETF HTTP working group adopted draft-ietf-httpbis-safe-method-w-body in 2021, initially to generalize SEARCH, renamed it QUERY by draft-02 in 2022 to shed the WebDAV baggage, and shipped RFC 10008 after fourteen draft revisions. The author list explains the industry buy-in: Julian Reschke (greenbytes, co-editor of the core HTTP specs), James Snell (Cloudflare), and Mike Bishop (Akamai). When the two largest CDNs co-author a caching-focused method, they intend to implement it.
How QUERY Works on the Wire
A QUERY request looks like a POST that tells the truth. Here's the RFC's canonical example — a form-encoded query against a contacts collection:
Beyond the basic exchange, RFC 10008 nails down four behaviors that make QUERY more than "POST, but pinky-promise it's safe":
1. Content-Type is not optional. Servers "MUST fail the request if the Content-Type request field is missing or is inconsistent with the request content." No content sniffing, no guessing — a sharp break from POST's anything-goes reality.
2. Discovery via Accept-Query. A server advertises QUERY support and its accepted formats with a response header using Structured Field syntax:
OPTIONS /contacts HTTP/1.1
Host: api.example.com
HTTP/1.1 204 No Content
Allow: GET, HEAD, OPTIONS, QUERY
Accept-Query: application/x-www-form-urlencoded, application/jsonpath
One subtlety worth knowing: the Accept-Query value "applies to every URI on the server that shares the same path" — the URL's query component is ignored for this purpose.
3. Results can get their own URIs. A 2xx response may include a Location header naming a URI you can later GET to re-run the equivalent query, or a Content-Location naming a resource that holds this specific result snapshot. That turns an expensive ad-hoc query into a shareable, bookmarkable, cacheable resource — a genuinely RESTful touch POST never standardized for reads.
4. Redirects behave like you'd hope. A 301 or 308 means repeat the QUERY at the new target; 303 means fetch the result with a plain GET. Crucially, the legacy exception that lets clients degrade a redirected POST into GET "does not apply to QUERY requests" — your query body survives the redirect.
Caching: The Actual Killer Feature
The RFC is blunt about the mechanics: "The cache key for a QUERY request MUST incorporate the request content and related metadata." URL plus body, hashed, stored. Identical query, identical key, edge-served response.
Caches are even allowed to normalize semantically insignificant differences — stripping content encoding, or applying format-aware knowledge (JSON key order, whitespace) — so trivially different bodies can still share a cache entry. If that makes you nervous, no-transform opts out.
Think about what this does for a search-heavy API. Today, your "cache" for POST /search is an application-level Redis layer you built, keyed by a hash you invented, invalidated by rules you maintain. QUERY moves that entire concern into infrastructure that already exists at every hop between the user and your origin. This is the same architectural instinct as moving analytics to the edge with Cloudflare Workers — push work to the layer that's already positioned to do it.
💡 Key insight: QUERY doesn't make anything possible that was impossible before. It makes the default correct — caching, retries, and semantics you previously had to hand-build now fall out of the method name.
QUERY vs GET vs POST
The one-table version, straight from the RFC's own comparison:
That security row deserves a sentence: because the query moves out of the URL, it stops leaking into access logs, browser history, referrer chains, and analytics pipelines. RFC 10008's Security Considerations calls this out as a real benefit for sensitive queries — with the matching warning that servers minting result URIs must not embed sensitive query parts back into them.
Where QUERY Works Today (July 2026)
The honest adoption picture, one month after publication:
On the working side: Node.js parses QUERY natively since 21.7.2 and 22+, and Fastify exposes it with one line. nginx landed basic upstream support, Spring Framework has an active PR (#34993), Rails has a live core proposal, and ASP.NET Core recognizes it in .NET 11 previews.
OpenAPI 3.2 also models QUERY operations — which means generated clients will offer it before most hand-written servers accept it.
Here's a working Fastify endpoint today:
import Fastify from 'fastify';
const app = Fastify();
app.addHttpMethod('QUERY', { hasBody: true });
app.route({
method: 'QUERY',
url: '/products',
handler: async (req, reply) => {
const results = await search(req.body); // body IS the query
reply.header('cache-control', 'public, max-age=60');
return results;
}
});
And from any client that lets you set a custom method:
curl -X QUERY https://api.example.com/products \
-H 'content-type: application/json' \
-d '{ "category": "keyboards", "maxPrice": 200, "sort": "rating" }'
The missing piece is the browser. fetch() can't send QUERY until the WHATWG Fetch spec adds it, and even then QUERY is not a CORS-safelisted method, so cross-origin requests will always preflight. In 2026, QUERY is a server-to-server and API-gateway story — which is exactly where search, reporting, and internal query traffic lives anyway. If you build backend-for-frontend layers in Node.js, that BFF-to-service hop is the perfect first deployment.
Common Mistakes to Avoid
The #1 mistake: treating QUERY as a POST alias
The method is a contract, not a vibe. If your QUERY handler writes an audit row, increments a rate counter that changes responses, or mutates anything a client could observe, you've broken the contract — and a cache or retrying proxy will eventually expose that bug in production, far from the code that caused it. Side effects that aren't client-observable (logging, metrics) are fine, exactly as with GET.
Four more, seen in the wild already:
-
Omitting
Content-Type. Legal-ish on POST, a mandatory failure on QUERY. Fail these requests loudly, as the RFC requires — don't sniff. -
Forgetting the CORS preflight. QUERY from browser-adjacent contexts will send OPTIONS first. Your gateway needs
Access-Control-Allow-Methods: QUERYor every request dies preflight. -
Leaking query content into result URIs. If QUERY returns a
Locationfor later GETs, that URL will be logged everywhere. Use opaque result IDs, not serialized query parameters. - Assuming your WAF and proxies pass it through. Older intermediaries reject unknown methods. Test the full path — one method-allowlist in a corporate proxy can 405 your rollout.
Should You Adopt QUERY Now?
FAQ
The Bottom Line
REST API design has spent 25 years contorting reads into methods that either couldn't carry the query or couldn't admit it was a read. The HTTP QUERY method ends that trade-off with the least glamorous, most durable kind of fix: a verb that tells the infrastructure the truth, and infrastructure that rewards honesty with caching and retries you no longer have to build.
You don't need to rewrite anything this quarter. But every new search, filter, or reporting endpoint you design from today should be QUERY-shaped: one query document in the body, a mandatory content type, and a handler with zero side effects. Do that, and adopting the verb itself — when your framework, gateway, and CDN all catch up — becomes a one-line change instead of a migration project.
If you found this useful, read Node.js Backend for Frontend Developers next — the BFF layer is exactly where QUERY will land first — or see how FastAPI's app.frontend() rethinks another old default.
Sources
- RFC 10008 — The HTTP QUERY Method (IETF, June 2026)
- draft-ietf-httpbis-safe-method-w-body — draft history (IETF Datatracker)
- RFC 9110 — HTTP Semantics (GET body semantics, method properties)
- RFC 5323 — WebDAV SEARCH (the 2008 precursor)
- Spring Framework PR #34993 — Add RFC 10008 (QUERY) support
- Ruby on Rails core proposal — Support for the HTTP QUERY method
- RFC 10008: HTTP QUERY Method Ends the POST Workaround (byteiota, adoption roundup)
Written for umesh-malik.com — no-fluff technical writing on AI, Web Dev, and Engineering.
Originally published at umesh-malik.com
Keep reading on umesh-malik.com:




Top comments (0)