Safeguard
Security Guides•

Should a GraphQL API accept GET requests, or POST only?

GraphQL servers must accept POST and may accept GET for queries. Compare caching gains against security trade offs and see which settings to review.

Safeguard Security Team
4 min read

Accept POST for everything and add GET only for read queries you want cached, ideally through persisted documents. The GraphQL project says servers must handle POST for queries and mutations and may accept GET for queries. A GET request puts the query in the URL, which is easier to cache and also easier to log, share and replay.

What the standard guidance says

The GraphQL project's page on serving over HTTP states that a GraphQL HTTP server must handle the POST method for query and mutation operations, and may also accept GET for query operations. For GET, the document goes in the query parameter of the query string, with variables as a JSON encoded string in another parameter.

It adds that GET may be used only for query operations. A mutation must use POST. It also notes that URL length limits in browsers and CDNs can be a problem for big queries, and that a common answer is to store documents on the server and send a short identifier, using persisted documents, automatic persisted queries or trusted documents.

Where the security trade offs come from

The following points are general web security reasoning rather than claims from the pages cited:

  • URLs travel widely. Query strings can appear in proxy logs, analytics, browser history and the referrer header. If a query or its variables contain anything sensitive, GET exposes it to those places.
  • GET should have no side effects. Browsers and caches treat GET as safe to repeat. That is why mutations must not be accepted over GET. Check that your server really rejects a mutation sent as GET.
  • Caches need care. A shared cache that stores responses for authenticated queries without varying by user can serve one person's data to another. Cache only responses meant to be public, and set cache control headers deliberately.
  • Cross site requests. GET requests can be triggered from other sites by a simple link or image tag. That is another reason read queries should be free of side effects and authorization should not depend on ambient state alone.

Comparison

AspectPOSTGET for queries
Allowed operationsQueries and mutationsQueries only
Variables locationRequest bodyURL parameter
CachingHarder by defaultEasier with CDNs
Log exposureBody usually not loggedURL usually logged
Size limitsLarge bodies fineURL length limits

Steps to decide

  1. List which clients call the API and whether any benefit from edge caching.
  2. If none do, disable GET and accept POST only. Simpler surface, fewer surprises.
  3. If some do, enable GET for queries and pair it with persisted documents so URLs carry a short ID, not query text and sensitive variables.
  4. Confirm mutations over GET are rejected with an error, and write a test for it.
  5. Set cache control headers on authenticated responses so shared caches do not store them.
  6. Scrub query strings from logs where variables might hold personal data, or avoid putting such variables in URLs at all.
  7. Require the expected content type on POST requests and reject others. The standard guidance describes application/json for the request body.

What this does not solve

Choosing the method does not fix authorization, depth abuse or batching. It only changes how the request travels. Keep your other controls in place. If you rely on cookies for authentication, review how your server handles requests from other origins as well.

Try it yourself

Click through it at your own pace, or open it full screen.

Look at how a dynamic scan exercises a running app, and think about testing mutations over GET.

Quick check

Can a mutation be sent with GET?

It should not be. The GraphQL guidance says GET may be used only for queries, so mutations must use POST. Test that your server rejects the other case.

Why do persisted documents come up with GET?

URLs have length limits, so short document identifiers replace long query text. That also keeps variables and query shapes out of long URLs.

Safeguard scans your dependencies and SBOMs for known vulnerabilities, including the HTTP and GraphQL libraries behind your API. A free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.