The Fastest Way To Decide
The easiest test is not “does this endpoint accept a body?” It is:
- is the client reading something
- or is the client submitting something that changes server state or triggers work
If it is a read, it should usually be GET. If it is a submission or action, it should usually be POST.
The Core Difference
GET and POST are the two most-used HTTP methods, and they express different intent:
- GET retrieves a resource. It should have no side effects on the server.
- POST submits data to the server, typically creating a resource or triggering an action.
This distinction isn’t just convention — it has real implications for caching, browser behavior, bookmarking, and API design.
Safety and Idempotency
These two properties define how methods should behave:
| Property | GET | POST |
|---|---|---|
| Safe (no side effects) | ✅ Yes | ❌ No |
| Idempotent (same result if repeated) | ✅ Yes | ❌ No |
| Cacheable | ✅ Yes | ❌ No (by default) |
Safe means the request doesn’t modify server state. A GET request should be readable without consequence — you can make it 100 times and the server state stays the same.
Idempotent means making the same request multiple times produces the same result as making it once. GET is idempotent: fetching /users/42 ten times returns the same user ten times. POST is not: submitting an order form ten times creates ten orders.
Request Structure
| GET | POST | |
|---|---|---|
| Parameters | Query string (?key=value) | Request body |
| Body | Not used (technically allowed, but ignored by most servers) | Required for data |
| URL length limit | Yes (~2000 chars in practice) | No practical limit |
| Visible in URL | Yes | No |
| Saved in browser history | Yes | No |
| Bookmarkable | Yes | No |
GET parameters appear in the URL: /search?q=http+methods&page=2. This makes GET requests bookmarkable, shareable, and cacheable — but it also means sensitive data (passwords, tokens) must never go in a GET URL.
POST data goes in the request body, which is not stored in browser history and not visible in the URL bar. This makes POST appropriate for form submissions, file uploads, and any operation that changes server state.
Caching
GET responses can be cached by browsers, CDNs, and proxies. A Cache-Control: max-age=3600 on a GET response means the browser won’t re-request that URL for an hour.
POST responses are not cached by default. Even if you return Cache-Control: max-age=3600 on a POST response, most caches will ignore it. This is intentional — POST implies a state change, and caching state-changing operations would be dangerous.
Browser Behavior On Refresh
When a user refreshes a page loaded via GET, the browser simply re-sends the GET request silently.
When a user refreshes a page that was the result of a POST (like a form submission), the browser shows a warning: “Resending this form will resubmit your data.” This is the browser protecting the user from accidentally submitting a form twice.
The standard pattern to avoid this is the POST/Redirect/GET pattern: after a successful POST, redirect the user to a GET URL. The browser then loads the confirmation page via GET, and refreshing it is safe.
When To Use Each
Use GET when:
- Fetching a resource (page, API data, file)
- The operation has no side effects
- You want the URL to be shareable or bookmarkable
- You want the response to be cacheable
- Building a search or filter interface
Use POST when:
- Creating a new resource
- Submitting a form
- Uploading a file
- Triggering an action with side effects (send email, process payment)
- The data is sensitive and shouldn’t appear in URLs or logs
Common Mistakes
Using GET for state-changing operations — a crawler, prefetcher, or innocent page refresh can trigger destructive behavior you never meant to expose as a read.
Using POST for every endpoint — that throws away caching, bookmarking, and the semantic contract clients expect from the web.
Putting sensitive data in GET parameters — URLs leak into logs, browser history, analytics tooling, and sometimes referrer headers.