GET vs POST: HTTP Methods Explained

GET and POST are the two HTTP methods you will use most often, whether you are building a web form, calling a REST API, or debugging a request in your browser's network tab. They look similar at a glance, but they signal different intentions to servers, proxies, and browsers — and choosing the wrong one causes bugs that range from broken back buttons to duplicated database records.

This guide explains what each method does, how it travels over the wire, the formal properties that distinguish them (safety and idempotence), and the practical rules for picking one. If you are new to HTTP itself, the broader what is an API primer is a good companion read.

What HTTP methods are

Every HTTP request begins with a method (also called a verb) that tells the server what kind of action the client wants to perform on a resource. The method is the first token on the request line, followed by the path and protocol version:

GET /products/42 HTTP/1.1
Host: example.com

The HTTP specification defines several methods — GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS — but GET and POST dominate because they are the only two that plain HTML forms support natively. The method is metadata about intent; it does not by itself guarantee the server behaves a certain way. A server can technically modify data on a GET, but doing so violates the spec and breaks assumptions that caches and crawlers rely on.

How GET works

GET requests retrieve a representation of a resource. All parameters travel in the URL as a query string, appended after a question mark and joined with ampersands:

GET /search?q=http+methods&page=2 HTTP/1.1

Because the data lives in the URL, a GET request is shareable, bookmarkable, and shows up in browser history and most server access logs. There is no request body in a standard GET. Values must be URL-encoded so that spaces, ampersands, and other reserved characters survive transit — see the URL encoding guide for the rules, and the URL Parser to inspect a query string component by component.

GET responses are cacheable by default. Browsers, CDNs, and intermediary proxies will happily store and reuse them, which makes GET fast and scalable for read traffic but a poor fit for anything that should run fresh every time.

How POST works

POST submits data to be processed by the target resource — creating a record, logging in, uploading a file, or triggering a side effect. The payload travels in the request body rather than the URL, so it is not visible in the address bar, browser history, or typical logs:

POST /accounts HTTP/1.1
Content-Type: application/json
Content-Length: 33

{"name":"Ada","email":"ada@x.io"}

A POST body can be almost any size and any format. The Content-Type header tells the server how to parse it. The two formats HTML forms produce are application/x-www-form-urlencoded (the default) and multipart/form-data (required for file uploads); APIs most often use application/json. POST responses are not cached by default, so each submission reaches the server.

GET vs POST at a glance

PropertyGETPOST
PurposeRetrieve dataSubmit data / cause an effect
Where data livesURL query stringRequest body
Visible in URL / historyYesNo
Bookmarkable / shareableYesNo
Cacheable by defaultYesNo
Practical size limitConstrained by URL lengthEffectively unlimited
SafeYesNo
IdempotentYesNo
Supports file uploadNoYes

Safety and idempotence: the properties that matter

Two formal concepts from the HTTP spec explain most of the practical differences. A method is safe if it is intended to be read-only and cause no state change on the server. GET is safe; POST is not. This is why search engine crawlers, browser link prefetchers, and antivirus scanners freely follow GET links but never auto-submit POST forms — a safe method should never accidentally delete an account or place an order.

A method is idempotent if making the same request once or many times produces the same server-side result. GET is idempotent: fetching the same URL twice returns the same resource without side effects. POST is not idempotent: submitting an order form twice can create two orders. This single property drives the most common POST pitfall, covered below.

Note that idempotent does not mean the response bytes are identical every time — a GET to a clock endpoint returns a new time on each call. It means no additional change of state results from repeating the request.

When to use each

Use GET when you are reading or querying data and the request has no side effects: loading a page, running a search, filtering a list, paginating results, or fetching a resource by ID. If a user should be able to bookmark the result, share the link, or hit the back button without warnings, GET is correct.

Use POST when the request changes state or carries sensitive or large data: creating records, authentication, posting comments, uploading files, or any action you would not want repeated by a refresh or a crawler. In REST APIs, POST conventionally creates a new resource, while PUT replaces and PATCH partially updates an existing one. For a quick lookup of every verb's intended semantics, the HTTP Methods Reference is handy.

Common pitfalls

Putting secrets in a GET query string. URLs are logged by servers, proxies, and analytics tools, and they sit in browser history. Never send passwords, tokens, or personal data as GET parameters — use a POST body. Note that neither method encrypts data on its own; only HTTPS protects the request in transit.

The double-submit problem. Because POST is not idempotent, refreshing a page after a POST re-sends the body, and browsers warn about resubmission. The standard fix is the Post/Redirect/Get pattern: after a successful POST, respond with a 303 redirect to a GET URL so a refresh re-fetches the result page rather than re-submitting the form. (See the HTTP status codes guide for which redirect status to return.)

Using GET to change data. Wiring a delete or logout action behind a GET link means a prefetcher, crawler, or a user mashing back/forward can trigger it unintentionally. State-changing actions belong on POST (or DELETE/PUT).

Hitting URL length limits. Browsers and servers cap URL length, so large payloads silently truncate or get rejected on GET. Anything sizable — long text, JSON documents, files — belongs in a POST body.

Forgetting to URL-encode GET parameters. Unencoded ampersands, equals signs, or spaces corrupt the query string and produce wrong or missing values server-side. Always encode user-supplied values.

Frequently Asked Questions

Slightly, but not because POST is encrypted — it isn't. POST keeps data out of the URL, so it avoids leaking into browser history, server access logs, and the address bar. But the body still travels in plain text unless you use HTTPS. For any real confidentiality, HTTPS is the requirement; choosing POST over GET only reduces incidental exposure.

The HTTP spec technically permits a body on GET, but it has no defined meaning, and many servers, proxies, and client libraries ignore or strip it. In practice you should never rely on a GET body — put parameters in the query string, and if you need to send a payload, use POST.

That warning appears when you refresh a page that was loaded by a POST. Because POST is not idempotent, re-sending the body could duplicate the action (a second order, a second comment). The fix is the Post/Redirect/Get pattern: after handling the POST, redirect to a GET URL so a refresh re-fetches that page safely.

There is no limit in the HTTP standard itself, but browsers and servers impose practical caps on total URL length. Exceeding it causes the request to be truncated or rejected, often silently. For large or variable-length data, use a POST body, which has no comparable constraint.

In REST APIs, POST typically creates a new resource and is not idempotent. Use PUT to fully replace an existing resource at a known URL — it is idempotent, so repeating it is safe. Use PATCH to apply a partial update. Plain HTML forms only support GET and POST, so PUT and PATCH are mainly used by JavaScript fetch calls and API clients.