The Core Difference
GET and POST are the two most-used HTTP methods, and they represent fundamentally different intentions:
- 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 — e.g., /delete-user?id=42. This is dangerous because browsers, crawlers, and prefetch mechanisms can trigger GET requests without user intent. A crawler indexing your site could accidentally delete data.
Using POST for everything — some developers avoid GET because they don’t want parameters in the URL. This breaks caching, bookmarking, and sharing. Use GET for reads.
Putting sensitive data in GET parameters — passwords, tokens, and PII in query strings end up in server logs, browser history, and referrer headers. Always use POST (or headers) for sensitive data.