📑 Contents
Overview / TL;DR Why It Was Needed Syntax & Basic Example Safety & Idempotency Content-Type & Errors Accept-Query & Discovery Caching Semantics Location & Equivalent Resource Redirects & Conditionals GET vs QUERY vs POST Security Considerations Ecosystem & Adoption (2026) Using QUERY in Code When to Use It ReferencesThe HTTP QUERY Method
RFC 10008 (June 2026) — the first new HTTP method standardized in over two decades. A safe, idempotent way to send a query with a request body, closing the long-standing gap between GET and POST.
1. Overview / TL;DR
QUERY is a new HTTP request method, standardized in
RFC 10008
(published June 2026 by J. Reschke, J.M. Snell, and M. Bishop under the IETF HTTPBIS working group).
It sits deliberately between GET and POST: like POST, it carries
a request body; like GET, it is explicitly safe and idempotent,
so it can be cached, retried, and prefetched automatically.
One-line definition: QUERY asks the target resource to process the enclosed request content as a read-only query and return the results — without the URI-length limits of GET or the "did this mutate something?" ambiguity of POST.
- ✅ Safe & idempotent
- ❌ No request body semantics
- Query lives in the URI
- ✅ Safe & idempotent
- ✅ Request body carries the query
- URI is optional / a resource path
- ⚠️ Not safe, not idempotent by contract
- ✅ Request body
- Semantics are opaque to intermediaries
This page is a from-source deep dive: it pulls directly from the RFC text and the working-group drafts that preceded it, plus the practical ecosystem status as of mid-2026 (which frameworks and servers actually support it, and what still needs manual wiring).
2. Why It Was Needed
Every API that supports rich filtering, search, or reporting eventually runs into the same fork: encode the query in the URI (GET), or smuggle it into a request body (POST). RFC 10008 spells out why both are unsatisfying.
The problem with GET + URI query parameters
- Unpredictable size limits — a request can pass through many uncoordinated intermediaries (proxies, load balancers, CDNs, WAFs), each with its own undocumented URI length cap. There is no reliable way to know in advance whether a complex query will fit.
- Inefficient encoding — structured or nested data (arrays of objects, boolean
expressions, full-text search syntax) is awkward and verbose once flattened into
application/x-www-form-urlencodedkey/value pairs. - Privacy / logging exposure — request URIs are logged far more readily than request content by proxies, servers, browser history, and analytics tools, and they show up in bookmarks. A URI-encoded query leaks more than the equivalent content in a body.
- Resource identity blow-up — under strict HTTP semantics, every distinct query string is technically a distinct resource identifier, which sits awkwardly with how people actually think about "the same search, different parameters."
The problem with POST
POST has no fixed safety or idempotency contract — RFC 9110 explicitly leaves both open. That means:
- A client (or an intermediary, or a cache) cannot tell, just from the method, whether a given POST is a harmless read or a state-changing write.
- Automatic retries are unsafe by default — if a connection drops mid-request, blindly resending a POST risks double-processing a mutation.
- Caches generally treat POST responses as non-cacheable or only cacheable under narrow, explicit conditions.
Earlier attempts to close this gap — SEARCH, REPORT, PROPFIND —
all originate from the WebDAV activity and tie their semantics to a generic application/xml
body, with "mixed feelings" (the RFC's own words) about reusing WebDAV machinery for general-purpose
APIs. QUERY was designed as a clean, media-type-agnostic alternative whose name directly captures its
relationship to the URI's query component.
3. Syntax & Basic Example
A QUERY request looks exactly like a POST at the wire level, except for the method token and the semantics that come with it. The request content is the query; its media type tells the server how to interpret it.
QUERY /contacts HTTP/1.1 Host: example.org Content-Type: application/x-www-form-urlencoded Accept: application/json select=surname,givenname,email&limit=10&match=%22email=*@example.*%22
HTTP/1.1 200 OK
Content-Type: application/json
[
{ "surname": "Smith",
"givenname": "John",
"email": "smith@example.org" },
{ "surname": "Jones",
"givenname": "Sally",
"email": "sally.jones@example.com" }
]
The request content is not tied to any single format. application/x-www-form-urlencoded,
JSON query DSLs, GraphQL documents, SQL fragments, or a custom application/jsonpath
media type are all valid — the server just has to declare (and enforce) what it accepts.
The request URI still matters: it identifies the target resource the query is run
against (here, /contacts), the same way a POST target identifies where data is submitted.
What's new is that the body's job is unambiguous — it is the query, not "maybe a query, maybe
a mutation, depends on the endpoint."
4. Safety & Idempotency
These two properties, inherited from RFC 9110's definitions, are the entire reason QUERY is useful to caches, proxies, and retry logic.
"QUERY requests are safe with regard to the target resource; that is, the client does not request or expect any change to the state of the target resource." A server that mutates state in response to a QUERY is violating the contract, not exercising a valid edge case.
"QUERY requests are idempotent; they can be retried or repeated when needed, for instance, after a connection failure." N identical requests have the same effect (none) as one.
Practically, this unlocks behavior that was never safe to apply to a generic POST:
- HTTP clients and load balancers can automatically retry a failed QUERY the same way they retry a GET, without a "was this already applied?" concern.
- Caches are explicitly permitted to store and reuse QUERY responses (see §7).
- Tooling (linters, API gateways, WAFs) can treat QUERY as read-only traffic for rate-limiting, auditing, and access-control purposes without inspecting the body's business logic.
5. Content-Type & Error Handling
Because the body is the query, the media type is not optional decoration — it is load-bearing. The RFC is blunt about this:
"Servers MUST fail the request if the Content-Type request field is
missing or is inconsistent with the request content."
The spec gives explicit guidance on which status code to use for which failure mode:
| Status | Meaning | Example trigger |
|---|---|---|
| 400 | Bad Request | Missing Content-Type, or content doesn't match the declared type |
| 415 | Unsupported Media Type | The resource doesn't understand this query format at all |
| 422 | Unprocessable Content | Syntactically valid query, semantically invalid (e.g. references a non-existent field or table) |
| 406 | Not Acceptable | Client's Accept header requests a response format the server can't produce |
This is a meaningfully richer error vocabulary than a typical GET-with-query-string endpoint, which usually collapses "malformed query" and "query about something that doesn't exist" into an undifferentiated 400.
6. Accept-Query & Discovery
A client needs a way to find out, ahead of time, whether a resource supports QUERY at all and which
query formats it accepts. RFC 10008 defines a new response header for exactly this,
Accept-Query, encoded as an HTTP Structured Field
(RFC 9651)
of type List.
HEAD /contacts HTTP/1.1 Host: example.org HTTP/1.1 200 OK Accept-Query: "application/x-www-form-urlencoded", "application/sql"
OPTIONS /contacts HTTP/1.1 Host: example.org HTTP/1.1 200 OK Allow: GET, QUERY, OPTIONS, HEAD
Media types in Accept-Query can carry parameters and wildcards
(*/* or type/*), the same as a client's own Accept header.
One subtlety worth internalizing: the value of Accept-Query applies to every URI
that shares the same path — the query component of the URI itself is ignored for this
purpose, since QUERY's own request content is what varies, not the URI.
7. Caching Semantics
Because QUERY is safe, its responses are explicitly cacheable — but the cache key can no longer be just the URI, since the query lives in the body.
"The response to a QUERY method is cacheable; a cache MAY use it to satisfy subsequent QUERY requests. […] The cache key for a QUERY request MUST incorporate the request content and related metadata."
Caches are allowed to normalize semantically-insignificant differences before computing that key —
stripping content-encoding, or normalizing format conventions such as a +json media-type
suffix — but any such transformation exists purely to compute the cache key. It never changes the
actual request sent onward. The RFC also flags the obvious risk here: a cache that normalizes
incorrectly, or too aggressively, can serve a stale or simply wrong response if two
content bodies that aren't really equivalent get folded into the same key (see
§9).
Mid-2026 reality check: most deployed CDN and reverse-proxy caching logic predates QUERY and has no concept of "hash the body into the cache key." Expect QUERY responses to pass through as effectively uncached until cache infrastructure catches up (see §10).
8. Content-Location, Location & Equivalent Resource
QUERY introduces the concept of an equivalent resource: a plain GET-able resource that represents a particular QUERY request (its target plus its content) and can be re-fetched with a normal, bodyless GET. Servers aren't required to expose this, but if they do, they signal it with response headers.
Content-Location — "here's a URI for exactly these results"
HTTP/1.1 200 OK Content-Type: application/json Content-Location: /contacts/stored-results/17 [ ...results... ]
This is a claim that a client can GET /contacts/stored-results/17 later to retrieve
this specific result set again.
Location — "here's a URI that re-runs the same query"
HTTP/1.1 200 OK Content-Type: application/json Location: /contacts/stored-queries/42 [ ...results... ]
This is a claim that a plain GET /contacts/stored-queries/42 will repeat the query
operation itself — useful for bookmarking a saved search or sharing a link without re-sending the
original request body.
If the original query content was sensitive (e.g. contained a customer's email or an internal ID), the RFC explicitly warns: the assigned URI SHOULD NOT encode any sensitive portion of that content, since URIs are logged far more readily than bodies.
9. Redirects & Conditional Requests
Redirect status codes
- 301 / 308 (permanent) and 302 / 307 (temporary) — the server
suggests the client repeat the same kind of request (another QUERY, with the same content)
against the new
Location. Unlike POST, a QUERY does not silently downgrade to GET after one of these. - 303 See Other — signals that the query's results can be fetched with a plain
GETagainst the URI inLocation, without resending the original content.
Conditional requests
The "selected representation" for a QUERY is defined the same way as for an equivalent GET, so
standard conditional headers — If-Modified-Since, If-None-Match, etc. —
work as expected: a conditional QUERY only returns a body when the condition is met.
Range requests
Byte-range semantics carry over unchanged from GET, but the RFC is candid that they're rarely useful
here — query result formats typically define their own pagination (SQL's
FETCH FIRST … ROWS ONLY, or a JSON API's limit/offset), and
clients are expected to use those instead of HTTP byte ranges.
10. GET vs QUERY vs POST
| Property | GET | QUERY | POST |
|---|---|---|---|
| Safe | yes | yes | not guaranteed |
| Idempotent | yes | yes | not guaranteed |
| Request body semantics | undefined | defines the query | defined per-endpoint |
| URI identifies the query itself | yes, by definition | optional (via Location) | no |
| Cacheable | yes | yes (body-aware cache key) | limited / opt-in |
| Auto-retry safe | yes | yes | no |
| CORS preflight required | no | yes (not a safelisted method) | no (for simple requests) |
| URI logging / privacy exposure | high (query in URI) | low (query in body) | low |
Why not reuse SEARCH, REPORT, or PROPFIND?
These predate QUERY and can express similar ideas, but the working group rejected reusing them for
two reasons stated directly in the spec: they originate from WebDAV, which the wider HTTP community
has "mixed feelings" about depending on outside a WebDAV context; and they tie their semantics to a
single generic application/xml body, whereas QUERY is media-type-agnostic — the query
format is a first-class, negotiable property of the request (see §6), not
baked into the method's own spec.
11. Security Considerations
Content-Location/Location) and the original query
contained sensitive content that can't be logged, that URI SHOULD be chosen so it
doesn't itself leak the sensitive parts of the request.OPTIONS preflight — same operational cost as a custom-method or
non-simple-content-type POST/PUT/DELETE today.12. Ecosystem & Adoption Status (mid-2026)
RFC 10008 is a finished Proposed Standard, but standardization and ecosystem support are two different clocks. As of mid-2026, here's the honest state of things:
| Layer | Status | Notes |
|---|---|---|
Node.js core (http/https) | supported | Landed in Node 21.7.2 — the low-level HTTP client/server can send and receive arbitrary methods including QUERY. |
| Express.js | manual routing | No first-class app.query() yet — tracked in an open GitHub issue. Custom methods can be routed today via app.use() + a method check, or app.all() with manual dispatch. |
| nginx / Apache | passes through, needs config | Both proxy QUERY through by default, but anything that allow-lists methods — limit_except blocks, WAF rules, security middleware — needs QUERY added explicitly or the requests get rejected. |
Browser fetch() | already works | No spec change needed — fetch(url, { method: 'QUERY', body }) already sends an arbitrary method today; it just wasn't a named, standardized method with defined semantics until now. |
| curl | already works | curl -X QUERY -d '...' https://example.org/contacts — curl has always allowed arbitrary -X method overrides. |
| CDNs / edge caches | not cache-aware yet | Most CDN cache-key logic still only considers the URI. A QUERY response is typically treated as an unrecognized method and passed straight through uncached until providers add body-aware cache keys. |
Practical takeaway: the wire protocol and the "can my HTTP client send this" question are already solved everywhere. The gap is entirely in server-side framework ergonomics (routing sugar) and shared caching infrastructure (CDNs, reverse proxies) — expect first-class framework support to roll out through 2026–2027 as adoption pressure builds.
13. Using QUERY in Code
Client: browser fetch()
const res = await fetch('/api/products', {
method: 'QUERY',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ category: 'shoes', maxPrice: 100, sort: '-rating' })
})
const products = await res.json()
Client: curl
curl -X QUERY https://shop.example.com/products \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'category=shoes&maxPrice=100&sort=-rating'
Client: Node.js (core http module)
import http from 'node:http'
const req = http.request('http://example.org/contacts', {
method: 'QUERY',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}, (res) => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => console.log(JSON.parse(data)))
})
req.end('select=surname,email&limit=10')
Server: Express (manual routing until native support lands)
Express doesn't yet expose app.query(), but the method still arrives on
req.method, so it can be dispatched by hand:
app.use('/contacts', (req, res, next) => {
if (req.method !== 'QUERY') return next()
if (!req.is('application/x-www-form-urlencoded')) {
return res.status(415).send('Unsupported query format')
}
const { select, limit } = req.body // parsed by a urlencoded body parser
const results = runContactQuery({ select, limit })
res.set('Accept-Query', 'application/x-www-form-urlencoded')
res.json(results)
})
Remember to add QUERY to any CORS Access-Control-Allow-Methods list and
to any reverse-proxy / WAF method allow-list — since it's a new token, anything that whitelists HTTP
methods needs to be told about it explicitly, or requests will be rejected before they reach your
application code.
14. When to Use QUERY vs GET vs POST
The operation is genuinely read-only and the query is complex, nested, potentially large, or sensitive enough that you don't want it sitting in a URI — full-text search, GraphQL-style queries, SQL-like filters, faceted search with many parameters.
The query is small, simple, and shareable-as-a-link is a feature you want (pagination, a handful of filter flags) — GET's URI-as-resource-identifier property is a genuine strength for bookmarkable, cacheable-by-CDN-today endpoints.
The operation actually changes state — creates, updates, triggers a side effect — QUERY's safety contract makes it the wrong tool the moment a request has a mutating effect.
You need this to work through every consumer's toolchain today without any adjustment — third-party CDNs, older WAFs, and rigid corporate proxies with strict method allow-lists may still reject or mishandle it until it's more broadly configured for (see §12).
References
-
1RFC 10008 — The HTTP QUERY MethodThe canonical, published Standards Track specification. Source for every normative claim on this page.
-
2draft-ietf-httpbis-safe-method-w-body (IETF Datatracker)The working-group draft history (versions 02–14) that led to RFC 10008 — useful for seeing how the design evolved.
-
3RFC Editor: Info page for RFC 10008Publication metadata, status, and errata tracking for the RFC.
-
4IETF Announcement: RFC 10008 on The HTTP QUERY MethodThe official ietf-announce mailing list publication notice.
-
5RFC 9110 — HTTP SemanticsDefines the base concepts QUERY builds on: safety, idempotency, conditional requests, and response status semantics.
-
6RFC 9651 — Structured Field Values for HTTPThe encoding format used by the new Accept-Query header field.
-
7expressjs/express #5615 — Support HTTP QUERY methodTracks first-class QUERY routing support in Express; current state of manual workarounds.
-
8nodejs/node #51562 — Support for 'QUERY' methodNode.js core tracking issue; confirms QUERY method support landed in the 21.x line.
-
9DEV Community: HTTP Just Got Its First New Method in 20 YearsAccessible practitioner write-up covering ecosystem/adoption context (nginx, Apache, CDNs).
-
10Hive Security: RFC 10008 and the Attack Surface Still Catching UpSecurity-focused analysis of QUERY's new risk surface — cache normalization, WAF gaps, injection concerns.