For years, many APIs have hidden complex searches behind POST. Not because it made semantic sense, but because it was the practical way out. GET works very well for simple reads, but when a search needs nested filters, arrays, ranges, multiple sorting rules or JSON structures, the URL stops being a comfortable place to put everything. The result became familiar to any backend team: read endpoints with a POST body.

HTTP has now filled that gap with RFC 10008, which defines the QUERY method as an IETF Proposed Standard. Its goal is clear: to allow a query request with a body, like POST, while keeping the properties expected from a read operation: it is safe, idempotent and cacheable.

This does not mean that every framework, proxy, load balancer, CDN and WAF will support it tomorrow without changes. Adoption will take time. But for those designing APIs, maintaining web infrastructure or dealing with advanced search endpoints, QUERY points in a very logical direction: stop using POST as a generic container for complex reads.

The real problem: GET falls short and POST slightly lies

GET is the natural method for requesting data. It is safe, idempotent and cacheable. Its problem appears when the query stops being simple. A URL can carry parameters, but it is not designed to transport large or highly expressive structures. Real-world limits do not depend only on the server, either. The request may pass through browsers, proxies, load balancers, gateways, firewalls, CDNs and observability systems, each with its own restrictions.

There is also a less visible detail: URLs are much more likely to be recorded in logs than request bodies. If sensitive filters are sent in the query string, they may end up in browser history, metrics, traces, referrer headers or intermediate logs.

POST solved the physical part of the problem because it accepts a body. You could send a clean JSON payload with well-structured filters without fighting URL encoding. But the price was semantic loss. For a proxy, a CDN, an HTTP client or a retry system, POST does not natively say “this is a safe read”. It may be a search, but it may also create an order, start a task, submit a form or modify state.

MethodSafeIdempotentBodyCacheableNatural use
GETYesYesNo defined semanticsYesSimple reads
QUERYYesYesYesYesComplex queries
POSTNot necessarilyNot necessarilyYesConditionalCreation, actions or processes with effects

In HTTP, “safe” does not mean encrypted, authenticated or protected against attacks. It means that the client is not asking to change the state of the resource. A GET or QUERY may still be logged, consume CPU or update metrics, but it should not create, modify or delete data as part of its main operation.

What QUERY brings

QUERY allows the content of the query to be sent in the request body. That content can be JSON, SQL, JSONPath, forms or another media type supported by the server. The semantics are not defined only by the method, but also by the resource and the Content-Type.

A simple example could look like this:

QUERY /api/servers/search HTTP/1.1
Host: example.com
Content-Type: application/json
Accept: application/json

{
  "where": {
    "region": ["mad1", "ams1"],
    "status": "active",
    "ram_gb": { "gte": 128 },
    "tags": ["proxmox", "production"]
  },
  "sort": [
    { "field": "created_at", "direction": "desc" }
  ],
  "limit": 50
}Code language: JavaScript (javascript)

Before QUERY, this usually ended up as something like:

POST /api/servers/search HTTP/1.1
Content-Type: application/jsonCode language: HTTP (http)

It worked, but the method was not telling the whole truth. QUERY does: the server will process a query included in the body and return the result, without the client expecting state changes.

The RFC also introduces the Accept-Query header, which a resource can use to indicate which formats it accepts for queries. For example:

Accept-Query: application/json, application/jsonpath, application/sqlCode language: HTTP (http)

This makes capability discovery possible without relying only on external documentation. A client could first ask with HEAD or OPTIONS, read Accept-Query, and decide whether to send JSON, a form or a query in another format.

Advantages for APIs, CDNs and retries

The first advantage is semantic clarity. An advanced search endpoint no longer has to disguise itself as POST. This helps API design, SDKs, documentation and teams operating infrastructure. The intention is clearer from the HTTP method itself.

The second advantage is idempotency. If a connection drops halfway through a QUERY request, a client or intermediary can retry it without fear of duplicating a purchase, creating two records or launching two jobs. This does not remove the need to design the backend properly, but it gives a much cleaner signal to the HTTP chain.

The third advantage is caching. QUERY is defined as cacheable. That opens an important door for expensive searches that today are executed again and again because they arrive as POST. The RFC requires the cache key to include the request content and related metadata. This is more complex than caching GET, but it is finally defined within the protocol.

AdvantagePractical impact
Structured bodyComplex filters without forcing them into the URL
Read semanticsBetter API design and contracts
IdempotencySafer retries after failures
HTTP cachingPossible reuse by proxies and CDNs
Less exposure in URLsFewer sensitive values in URI logs
Discovery with Accept-QueryThe server can announce supported formats
Content-Location and LocationResults or queries can become GET resources

One interesting possibility is for the server to answer a QUERY request with Location or Content-Location. This can assign a URI to a stored query or its result, allowing the client to use GET afterwards. It is useful for heavy reports, recurring searches or queries that are worth materialising.

Disadvantages and adoption problems

QUERY is not magic. The first problem is real-world support. Many servers, proxies, CDNs, WAFs, libraries, middleware and monitoring tools are used to GET, POST, PUT, PATCH and DELETE. A new method may be blocked, logged incorrectly, misclassified in metrics or treated as suspicious traffic.

The second problem is caching. Yes, QUERY is cacheable, but caching it properly requires infrastructure that understands the body. Looking only at the URL is not enough. Two JSON bodies with the same meaning but different key order or whitespace could generate different cache keys if they are not normalised. The RFC accounts for this complexity, but bringing it to production will require serious support from CDNs and proxies.

The third point is CORS. In browsers, QUERY is not one of the “simple” CORS methods, which are limited to GET, HEAD and POST. Cross-origin calls will require a preflight request with OPTIONS, and APIs will need to respond with Access-Control-Allow-Methods: QUERY where appropriate.

Risk or limitationWhat to review
Server supportNginx, Apache, Envoy, HAProxy, Node, Go, Java, .NET
CDNs and proxiesBody-based caching, keys, normalisation and purging
WAFsRules that block unknown methods
ObservabilityLogs, metrics, traces and dashboards
CORSPreflight and Access-Control-Allow-Methods
SDKsClients generated from OpenAPI and other tools
Backward compatibilityTemporary POST fallback
SecuritySize limits, validation and cost control

It is also worth remembering something basic: putting filters in the body does not make them secret. It is better than exposing them in the URL in some cases, but they still travel to the server and may end up in application logs, traces, APM systems or dumps if logging is not controlled. TLS, logging policies and data minimisation remain mandatory.

When to use GET, QUERY or POST

The practical rule can be quite simple. GET remains the best option for simple, stable reads that can be naturally represented in a URL. If a search fits cleanly in a query string, there is no need to complicate it.

QUERY fits when the operation is a read, but the input needs structure. This includes advanced search, inventory filters, analytics, reports, log queries, vector search, read-only GraphQL or reporting endpoints with many parameters.

POST should remain for what truly implies action: creating resources, submitting forms, launching processes, executing commands, changing state, starting flows or performing operations that are not safe. It can also remain the fallback for years while the ecosystem adopts QUERY.

CaseBest method
/users?status=active&page=2GET
Searching servers by tags, region, RAM and dateQUERY
Analytics query with nested filtersQUERY
Read-only GraphQL queryQUERY, when supported
Creating a userPOST
Launching an on-demand backupPOST
Generating a report that modifies state or consumes a non-repeatable quotaPOST
Updating a full resourcePUT
Partially modifying a resourcePATCH

For system administrators, the initial recommendation is not to enable QUERY in production blindly. The sensible approach is to test it first in controlled environments: internal APIs, staging, a specific gateway or new endpoints where proxy, WAF, cache, APM and client behaviour can be measured.

A minimal guide to getting started

A cautious design could follow these steps:

StepRecommendation
1Identify POST endpoints that are actually reads
2Separate safe operations from actions with effects
3Define a strict Content-Type, such as application/json
4Publish Accept-Query on resources that support it
5Apply body size and complexity limits
6Normalise queries if they are going to be cached
7Configure CORS, WAF, logs and metrics
8Keep POST fallback while clients migrate

A well-designed response could include caching and discovery headers:

HTTP/1.1 200 OK
Content-Type: application/json
Accept-Query: application/json
Cache-Control: public, max-age=60
Content-Location: /api/servers/search-results/8f7a21
Vary: Accept, Content-TypeCode language: HTTP (http)

The delicate part will be the cache key. If QUERY is cached in a CDN, the key must take into account the body, the Content-Type and any header that changes the response. Otherwise, there is a risk of serving incorrect results. For searches with user permissions, you will also need private cache, variation by identity or no caching at all.

The change will be slow, but necessary

QUERY will not replace GET or POST. It organises them. GET will remain perfect for simple reads and shareable URLs. POST will remain the natural method for actions and resource creation. QUERY occupies the space that had been empty for years: safe queries with a body.

Its adoption will depend less on the RFC and more on infrastructure. When Cloudflare, AWS, Fastly, Nginx, Envoy, HAProxy, backend frameworks, HTTP clients and OpenAPI tools start treating QUERY as a first-class citizen, the pattern will enter real architectures. Until then, teams will need to live with POST for complex reads and design migrations calmly.

The update matters because HTTP does not change every day. And when it changes to correct a practice that millions of APIs had normalised, it is worth paying attention.

For years, putting complex filters inside POST was a practical solution. Now it is starting to look like semantic debt with a way out.

Frequently asked questions

Does QUERY replace GET?
No. GET remains the best option for simple, cacheable reads that can be represented in a URL. QUERY is designed for read queries that need a body.

Does QUERY replace POST?
No. POST remains the right method for creating resources, launching actions or running operations with effects. QUERY is for safe and idempotent queries.

Can I use QUERY in production now?
It depends on your stack. You first need to validate support across servers, proxies, CDNs, WAFs, HTTP clients, observability and CORS. For many environments, internal pilots will be the best starting point.

Is QUERY more secure because it does not put filters in the URL?
Not in the cybersecurity sense. It reduces accidental exposure through URLs and intermediate logs, but the body can still be logged by applications or tracing systems. TLS, logging control and validation remain necessary.

Scroll to Top